65.9K
CodeProject 正在变化。 阅读更多。
Home

Expression Blend 和 Silverlight 中的 ListBox 样式(第 3 部分 - 附加模板)

starIconstarIconstarIconstarIconstarIcon

5.00/5 (37投票s)

2010年5月5日

CPOL

20分钟阅读

viewsIcon

134530

downloadIcon

5307

ListBox 附加模板和生成内容的解释和示例。涵盖布局、过渡和动画。

引言

欢迎阅读我的第七个 Expression Blend 和 Silverlight 初学者教程。这次,我们将通过附加模板查看ListBox生成内容样式设置,我将尽力指导您完成此操作。

再次重申,在开始本教程之前,我建议您阅读我以前的 CodeProject 教程。我正在将它们作为系列教程编写,因此,本教程将假定您已具备先前的知识。

我们目前涵盖了哪些内容?

在本教程的上一部分中,我们讨论了控件模板以及它如何有效地构成 ListBox 的边框/框架/舞台。我们对这些元素(主要是 ScrollViewer)进行了样式设置,以适应 ListBox 的预期用途/环境,无论它们是什么……我也不知道,所以我给应用程序添加了一个框架以提供一些上下文。但是如果我们回顾一下之前的教程,我们会发现这只是强调了 ListBoxTreeView 的内容并没有真正匹配新的 Style

TreeView 中的黄色文件夹图标与颜色方案不符,ListBox 中的蓝色超链接文本也不符。此外,当应用程序运行时,文件和文件夹的鼠标悬停状态是淡蓝色。以及 ListBox 上溢出到边框面板(ScrollContentPresenter)之外的矩形选择区域。现在,ListBox 控件模板中的任何内容都不会对我刚刚提出的问题产生任何影响。原因是控件模板与 ListBoxTreeView(或任何其他 Control)的生成内容无关。它所做的只是设置 Control 的舞台(框架/边框)并容纳 ScrollContentPresenter,后者是通往生成内容这个虚构世界的门户。我称之为虚构,因为如果没有内容,它都是隐形的!所以感谢你可能祈祷的任何人提供的示例数据,因为它对于设计生成内容的 UI 来说确实非常棒。另外,你可以与你的开发人员交谈,他们可以创建特定的设计时示例数据源,就像 defwebserver 在这里所做的一样

附加模板快速概述

让我们看看 ListBox 的附加模板,并尝试理解每个模板的作用。

基本上,我们有三个额外的模板,它们控制和操作出现在 ScrollContentPresenter 中的生成内容。每个模板在呈现和格式化生成内容和数据方面都有不同的作用或目标。下面是一个面向 UI 设计师的模板关系简化图。

ListBox 模板简化图 - 专为设计师设计,而非程序员!

项目面板模板

我们基本上在项目面板模板中包含项目模板项目容器样式模板。尽管项目面板在可用模板列表中排在第三位,但它“某种程度上”是其他两个模板的父级,因为它定义了它们作为一个整体如何布局。这可以是 StackPanel(默认)、WrapPanelDockPanel。基本上,任何继承自 Panel 类的东西都可以。您也可以指定 GridCanvas,但意义不大,因为项目模板的每个实例只会相互堆叠……

恕我直言:项目面板模板是 ListBox 用于布局在项目模板中定义的生成项目的 Panel。默认情况下,这是一个 StackPanel,但这可以根据您的数据和要求进行更改。

编辑项目面板模板最简单的理由是,将 StackPanel 的方向从 Vertical 更改为 Horizontal。或者,可能将其设置为 WrapPanel,但请注意,这可能会导致选择导航出现问题。(我正在等待一位朋友 (Jason Young) 博客他的解决方案,所以一旦有更新就会发布!)

项目模板

在这里,我们排列构成生成内容实例的不同元素。这可以是像 Icon/ImageTitle、伴随的 DescriptionCheckBox 等……你可以想到的任何东西,都可能是可以在项目模板中布局的元素之一。

在我们的应用程序中,defwebserver 在一个水平 StackPanel 中设置了一个 Image 和一个 HyperlinkButton

这个例子可能是最基本的了,我们当然可以做得更多,这将在本文后面介绍。

项目容器样式模板

这无疑是三个可用模板中最有趣的一个,所有神奇的事情都发生在这里。因为在这里,我们通过与用户互动来制作具有视觉吸引力的动画和效果!

此模板的默认设置如上图所示。除了用于各种视觉状态的一些矩形外,我们还有一个 ContentPresenter,它从项目模板获取输入。请注意,在“返回范围”图标旁边,此模板实际上称为“ListBoxItem 模板”,而在其上方的项目模板部分的屏幕截图中,在“返回范围”图标旁边。它实际上称为“ContentPresenter 模板”。忽略“SilverlightFileTemplate”,因为defwebserver在编辑原始模板的副本时创建了这个名称。所以你可以说前面图表中显示的模板排列应该更像下面的图表

imgDa.jpg

无论您如何看待它,我们最可能对项目模板感兴趣,以布局我们的生成内容,以及项目容器样式模板来与此生成内容交互。我们使用视觉状态管理器 (VSM) 操作项目容器样式模板,如下图所示,我们拥有的状态组比以前处理按钮时多……

显而易见的补充是一个名为“LayoutStates”的状态组,正如您所期望的,它可用于控制此模板中的元素在其 LoadedUnloaded 状态期间。不那么明显的是 Blend 4 中添加的效果,它允许状态组中状态之间的一些有趣的过渡。

项目容器样式模板需要考虑的另一件事是,它有一个关联的样式应用于它,这与 ListBox 控件模板样式不同。

因此,一个 ListBoxItem 可以应用不同的样式,同时仍然使用相同的周围 ListBox。所以,而不是拥有一个全新的 ListBox,具有不同的生成内容交互、颜色和样式,可以只向 ListBox 传递一个新的 ListBoxItem 样式来改变交互、颜色和模板元素。

概述总结

这就是 ListBox 的三个附加模板的概述,如果您是第一次接触它们,可能会有点困惑。因此,最好的记忆方式是这些模板并不是真正的平等,您可能通过它们在附加模板列表中的排列而产生这种误解。它们基本上是相互嵌套的,但顺序与附加模板列表中显示的顺序相反。

基本上,沿着内容演示器,从 ListBox 控件模板中 ScrollViewerScrollContentPresenter 一直进入 Items Panel Template(也称为 ItemsPresenter Template)。然后,这将 dẫn 到 ItemContainerStyle 的内容演示器,它从 Item Template 获取其生成内容。因此,如果我们再次查看我们的图表,我们应该从中心向外看,以理解生成内容是如何呈现样式化的。

Dc.jpg

此外,图中的紫色部分表示样式在 ListBox 控件中的放置位置。请再次理解,这是一个面向“设计师”的附加模板简化视图。

让我们开始吧!

为了开始编辑一些附加模板,我将从 defwebserver 的拖放文件管理器文章中接手,将其作为起点,通过附加模板格式化生成内容。

为了保持趣味性,因为我已经厌倦了它,并且为了释放更多“屏幕空间”,我再次改变了应用程序的外观。所以它有一个更薄的框架,折叠的铆钉(未移除),以及一个新的蓝色配色方案。

我还用几个铆钉样式化了 GridSplitter,并将其与 PictureFrameControl 集成。那些眼尖的人会注意到我用新的扩展器和文件夹图标对 TreeView 进行了一些样式化。我这样做只是为了在我们处理 ListBox 时不分散应用程序的注意力。

所以从这里下载更新后的应用程序,我们就可以开始了!

项目面板模板

我们首先来看看这个模板,因为它是这三个模板中最不有趣的,而且在很多情况下可能根本不需要任何编辑。选择 ListBox,然后选择 编辑附加模板 > 编辑项目布局 > 创建空模板

将模板命名为“ListBoxItemsPanelTemplate”,然后点击“确定”。

现在,如果我们查看对象和时间线,我们可以看到这是一个 ItemsPresenter 模板,正如我之前所说,这个模板控制/定义了控件模板中 ScrollContentPresenter 设置的区域的布局。

如上图所示,项目面板模板中只有一个 StackPanel,其默认方向为 Vertical

所以选择 StackPanel 并将 HorizontalAlignment 从“Vertical”更改为“Horizontal”,如下图所示。

这应该会改变画板中的 ListBox,以便在 ListBox 中只显示第一个生成的项目。其他生成的项目现在位于第一个项目的右侧,形成一个长流。这对于股票行情应用程序可能很棒,项目从右向左滚动,或从左向右滚动,但对于此应用程序来说并不合适。项目面板模板另一个非常酷的功能是能够将布局样式更改为 WrapPanel。我在这里不会这样做,因为它需要更多的解释,如果您不确定 WrapPanel 的功能,请查看 Microsoft Mix10 的这个视频

现在将 StackPanelHorizontalAlignment 改回“Vertical”,然后退出项目面板模板。

(借用巴布拉迪警官(南方公园)的话:“大家走吧,没什么可看的。”)

因为项目面板模板e 的内容差不多就是这样了!

项目模板

为了打破我在概述部分讨论模板的顺序。我们将在处理项目容器样式模板之前先查看项目模板。如果您一直专心致志并理解了我迄今为止关于模板的说法,您应该意识到,为了在项目容器样式模板中样式化生成内容,我们首先应该在项目模板中格式化生成内容。

defwebserver 在此应用程序中为我们提供了一些生成内容,但为了正确演示我们可以在项目模板中执行的操作,我希望有更多的示例数据可供使用,我已经在下载的项目中设置好了。

所以转到“数据”选项卡,选择“集合”,然后将其拖到画板中的 ListBox 上。

这应该会更改 ListBox 的示例数据,希望能与下图相同。

我们现在有了更多的生成内容,但目前它是一团糟。

所以选择 ListBox 并选择 编辑附加模板 > 编辑生成项目 > 编辑当前

这将带我们进入项目模板,其中显示了 StackPanel 中的所有示例数据。

现在为了更清楚,按如下图所示重命名项目。

示例数据已按其在数据选项卡中出现的相同顺序导入。)

我首先要做的就是将 StackPanelOrientation 更改为 Horizontal,并更改这些项目的整体布局,使它们从左到右堆叠

在画板中,您现在应该会看到一个 CheckBox,它的右侧有一个 Image,图片的右侧有一些 Text

现在在对象和时间线中,将图像拖到 CheckBox 上方,以更改它们在 StackPanel 中显示的顺序。

在仍选中图像的情况下,将 WidthHeight 都更改为 32,以缩小图像大小。

现在同时选择 ItemDescriptionItemTitle 元素,右键单击并选择 分组到 > StackPanel

在“对象和时间线”中,将新的 StackPanel 拖到“购买CheckBox 的上方,以更改父 StackPanel 的顺序。

展开子 StackPanel,选择 ItemTitle,并将其拖到 ItemDescription 元素上方,以更改此 StackPanel 的顺序。

选择 ItemTitle 上方的 StackPanel,将其 Orientation 更改为 Vertical,并仅在左侧设置 4 的 Margin

(确保 StackPanelWidthHeight 都设置为 Auto)。

现在选择 ItemTitle,将 Font 更改为粗体,大小更改为 7 pt

所以我们现在有一个水平“父级”StackPanel,元素从左到右排列。在这些水平元素的中间,我们有一个垂直 StackPanel,其中一个元素排列在另一个元素的下方。希望您开始明白这个模板中发生了什么,并且已经注意到,当我们编辑顶部项目模板时,所有显示在下面的项目模板实例都会自动根据我们对项目模板的编辑进行更新。您还应该意识到 StackPanel布局方面有多么有用,我现在将做更多演示。我们仍然有三个元素在项目模板中不可见,因为它们位于包含 TitleDescription 文本的 StackPanel 的右侧,因此超出了屏幕。所以我们需要格式化 TitleDescription 文本,使其能够换行并占用更少的水平空间。但我也希望 ItemTitle 文本的长度不被打断,并流过(上方)所有其他后续元素(独立于 ItemDescription 文本)。

所以选择 ItemDescription 元素并选择 分组到 > StackPanel,并将 StackPanelOrientation 设置为 Horizontal

再次选择 ItemDescription,将字体大小更改为 7pt,并在高级属性中将 TextWrapping 更改为“Wrap”。

现在将 ItemDescription 元素的 Width 更改为 140,并确保父 StackPanelWidth 设置为 Auto。同时选择 BuyStockQuantityStockTitle 元素,然后选择 分组到 > StackPanel

确保 StackPanelOrientation 设置为 Vertical,并按 StockTitleStockQuantityBuy 的顺序重新排列。

接下来,在对象和时间线中,将最新的 StackPanel 拖到其上方的 StackPanel 内部,使其直接位于 ItemDescription 下方,如下图所示。

(确保最新的 StackPanelWidthHeight 都设置为 Auto,并且 Margin 都设置为 0)。

选择 StockTitle 元素,将字体大小改为 7 磅,并将文本设为粗体。现在将 StockQuantity 字体改为 7 磅,并将文本设为斜体。当应用程序运行时,结果应该如下图所示

(我已经将我的 ItemTitle 文本更改为 9 磅,以清楚地显示它流过并跨越其内部和下方的子 StackPanel。)

希望我已经充分演示了项目模板,让您了解这个模板完全是关于布局的。以及项目模板中 StackPanel 的灵活性。显然,我们可以使用边距进一步分隔和格式化我们的项目,并将元素分组到网格中。但我会让您进一步探索……(编辑当前元素,添加更多元素,并根据您的需要格式化所有这些元素。)但是,我需要继续研究项目容器样式模板!

但在我们开始项目容器样式模板之前,我想放弃我们目前所做的所有更改。这些只是为了演示目的,而不是 defwebserver 和我正在开发的正在进行的应用程序的一部分。

所以重新加载原始的未编辑项目,再次进入 ListBox 的项目模板。

现在在资产中,找到我“快速”创建的“PageIcon”,并将 PageIcon 的副本插入 StackPanel 中。

PageIconWidth 设置为 14 像素,Height 设置为 16 像素。在对象和时间线中,将其重命名为“PageIcon”,并将其拖到 StackPanel 列表的顶部,位于 ImageHyperlinkButton 的上方。

画板中,我们现在应该有两个“页面”图标。

我创建的蓝色图标更适合我们的项目。此外,它还可以编辑,可以随我们的项目改变颜色。所以删除第二个白色 PageIcon,因为它不再需要了。在剩余的 PageIcon 上,在Left 侧设置 4 的 Margin,使其与 ListBox 的边缘保持距离。现在选择 HyperlinkButton,并在Left 侧也设置 4 的 Margin,使其与 PageIcon 保持距离。将 HyperlinkButton 的前景色更改为 Black,使其与 TreeView 项目的文本颜色匹配。

HyperlinkButton 可以通过其自身的模板样式进行进一步编辑,如果需要的话。)

现在我们只需要在 ListBox 中的项目列表上方设置一些自由空间,所以选择 StackPanel 并在 Top 设置 9 的 Margin。但是因为我们将此 Margin 应用于项目模板,所以此 Margin 应用于每个 Item,将它们全部隔开。

我们不能在项目模板中仅为一个 Item 设置 Margin,我们在这里所做的一切都将应用于每个项目。所以,相反,将顶部边距更改为 0,将底部边距更改为 1(为每个 Item 提供一点间距,并与 TreeView 项目间距匹配)。

现在转到 ListBox 控件模板,选择 [ItemsPresenter] 并将顶部边距设置为 8。

这应该会整体上拉开项目顶部的间距,而不是单个项目的间距。

项目容器样式模板

这就是我一直期待讨论的模板,部分原因是我把它留到了最后。但在我们进入这个模板更高级和有趣的部件之前,我们需要对鼠标悬停选中状态进行一些基本格式化。

所以选择 ListBox 并选择 编辑附加模板 > 编辑生成项目容器 > 编辑当前

(或者,如果您选择,则选择编辑副本模板)。

对象和时间线中,选择 fillColor 元素。

现在进入 VSM,选择 MouseOver 状态并将元素 不透明度 更改为 100%。

画板中,第一个项目现在应该有一个淡蓝色背景,如下图所示

返回到基本状态,然后选择 MouseOver 状态旁边的眼睛符号。

(这将允许我们编辑 fillColor 元素,而无需设置任何关键帧。)

fillColor Rectangle 的 X 和 Y 半径都更改为 5,以使 Rectangle 的角变圆。将左边距和右边距更改为 3,将上边距更改为 1。现在运行应用程序,在 MouseOver 状态下,选中的项目应该如下图所示

回到 Blend,选择 MouseOver 状态并将元素 Opacity 设置回 35%。现在选择 fillColor2 元素,并在 Base 状态下,单击 Selected 状态旁边的眼睛符号。

正如我们之前所做的那样,将 fillColor2 Rectangle 的 X 和 Y 半径都更改为 5,并将左边距和右边距更改为 3,上边距更改为 1。对 FocusVisualElement 重复相同的过程,对角应用半径,并设置侧边距。

项目容器样式模板的疯狂应用

现在到了有趣的部分,为我们的 ListBox 应用一些夸张的“过度”效果。其中大部分显然不适用于实际应用程序,使用效果动画时要记住,它们是为了增强您的应用程序,而不是分散对应用程序消息或目的的注意力!它们在前几次可能看起来很有趣和令人愉快,但这很快就会让用户感到沮丧和恼怒。所以不要得意忘形……

但是,我在这里会完全“过头”,只是为了演示可以完成什么!!!

我们先看看 MouseOver 状态,或者说是名为“CommonStates”的状态组。我们在这里应用的任何效果都将应用于此状态组中的所有状态。

为 MouseOver 状态应用效果也将应用于 Normal 和 Disabled 状态。但与其讨论这些,不如让我们继续看看实际效果……

单击效果图标“fx”,然后选择涟漪。(或者您喜欢的任何其他效果!)

将效果持续时间设置为例如 1 秒,然后运行您的应用程序查看结果。

当我们将鼠标悬停在 ListBox 项目上时,会产生涟漪效果。当 ListBox 项目返回到其正常状态(鼠标移开)时,我们也会得到相同的效果。

自己尝试不同的效果,调整持续时间以适应,并尝试不同的缓动函数

接下来,让我们看看 SelectionStates,特别是 Selected State

选择一个您喜欢的特效,并设置该特效的持续时间。我选择了“从左到右滑入”,因为这在截图中很容易显示!

运行您的应用程序,并使用箭头键更改选定项目。

看看这如何影响选中状态和未选中状态。这可能不是您想要的,因为您可能不希望在未选中项上发生滑入。我们可以通过向选中状态添加过渡来控制这一点。

通过从选中状态 > 所有其他状态添加过渡,我们可以在取消选中项目时应用完全不同的效果。

所以为了演示,我为此过渡添加了一个新的“百叶窗”效果,持续时间为 1 秒。

现在,当我们取消选择一个项目(鼠标移开)时,而不是“滑入”效果,我们得到的是“百叶窗”效果,如下图所示

我们显然可以在所有状态组中这样做,因此效果可以根据您的确切需求进行定制。

(或者在过渡中完全没有效果,如果持续时间设置为 0)。

最后,在本节中,我想看看 ListBox 项目加载的 LayoutStates

选择“BeforeLoaded”过渡,设置持续时间为 1 秒,缓动函数为“Bounce Out”。

现在,确保您已选择根网格,在变换部分,将 X 轴上的平移设置为 250。

现在运行应用程序,希望在加载过程中,ListBox 项目从右侧流入并从 ListBox 的左侧反弹。

(点击刷新或 F5 重新加载并再次显示动画。)

没有必要提供屏幕截图,所以如果您没有按照教程操作,请下载完成的项目!

就是这样

我的“过度”附加模板解释到此结束。回到defwebserver!请投票作废那些不敢留下评论说明我如何改进我的文章/教程的 3 星投票者!!!

© . All rights reserved.