WPF和Silverlight编程模型中一个强大无比的功能,就是能够完全定制所使用的控件的观感(Look and Feel )。这允许开发人员和设计师对控件的界面以微妙和戏剧性的方式进行精雕细琢,促成无比的灵活性以创建出恰如所愿的用户体验。
在这篇教程里,我们将看一下你可以定制控件的几种方式,然后在结尾使用这些技术对我们的Digg应用的用户界面润色一下。
在这个系列的第一部分里,我们在页面上加了一个简单的按钮控件,示范了如何把它的内容设成一个自定义的“Push Me!”文字字符串。然后我们连接了一个Click事件处理函数,在它被点击时执行一些代码:
这导致按钮在浏览器里象下面这么显示:
关于按钮控件,也许会让你感到惊奇的一件事情是,它的Content属性,不必是象“Push Me!”这样简单的字符串。实际上,我们可以把Content属性设成我们想要的任何形状或控件序列:
譬如,我们可以嵌入一个StackPanel,内含 <Image> 和 <TextBlock> 控件:
这会导致我们的按钮在运行时看上去会象下面这样。注意,它依然保留同样的功能行为(按它的话,按钮会陷下去,点击事件处理函数也会象以前一样触发):
我们也可以使用形状控件(象下面这样的Ellipse控件)来在按钮里面创建自定义的矢量图像:
注意上面我是怎么使用一个偏移RadialGradientBrush来加一个非常好看的反射式光泽来填充Ellipse控件的:
我们甚至可以搞些古怪,在按钮内嵌入可交互的象日历这样的控件:
在上面的例子中,日历控件是完全可以交互的,意味着终端用户可以前后翻月历,在日历里选择一个日期,然后按其中的按钮,触发Click事件处理函数:(注:我不清楚这是否会是一个好的用户体验,但它确实展示了你所能做之灵活性!)
我上面概述的这些类型的内容定制场景不仅对按钮控件有效,同样地对其他继承自ContentControl基类的其他控件也工作。
为Silverlight 和 WPF所用的控件模型,所允许之定制,远远超出控件内部的内容。它还允许你用你想要的任何东西完全替换控件的视觉树(visual tree),同时还保持控件的同样行为。
例如,我们不想要我们的按钮拥有一个默认的长方形的按钮的外观,而是要它们有一个象下面这样的自定义的圆形按钮外观:
我们可以这么做,在App.xaml文件中创建一个“RoundButton”样式,在其中,我们将改写按钮的Template属性,提供一个内含一个Ellipse控件和一个TextBlock的ControlTemplate来替换按钮的默认长方形外观:
然后我们可以让<Button>引用这个Style资源来使用这个“RoundButton”的观感:
在控件模板中融入内容
你也许会注意到一件事情,在上面的“RoundButton”控件模板中,按钮的大小,以及显示在其中的内容,都是写死的(总是“Push Me!”)。
好消息是,WPF 和 Silverlight也能让我们对这些设置进行定制。我们可以在控件模板中通过使用 {TemplateBinding ControlProperty} 的标识扩展句法 (markup extension syntax) 来绑定到控件的属性来实现。这允许我们的控件模板随着外部开发人员设置在控件的属性而改变:
注意上面,不是加 <TextBlock>控件来显示内容,而是使用<ContentPresenter>控件。那会允许我们不光让按钮显示文字字符串,而且可以显示任何自定义的内容(就象我们在本教程早先时候做的那样)。
然后,我们可以在下面的三个按钮上使用上面的Style(每个按钮都有不同的内容和属性设置):
上面的按钮然后就会象下面这样显示(对了,缩小的日历控件还支持翻页和日期选择!):
如果我们想进一步,我们还可以往ControlTemplate中加故事板动画(来处理象“hover(悬浮)”,"focus(得到焦点)", "pushed(按下)"这样的按钮状态)。这个能力允许我们创建非常优美的用户交互场景,同时还能促成HTML中不能实现的场景。
在应用中操作控件的开发人员可以对所有这些样式和控件交互定制保持一无所知,他们还可以依然如故地处理控件的事件和操作控件的对象模型,而让设计师另外使用样式和模板对控件的观感进行精雕细琢和定制。
至此,我们讨论了控件模板工作原理的一些基础知识,让我们来在几个地方用它们来给我们的Digg应用的UI加些点缀。
目前,应用中一个明显需要一些加工的地方是我们用户控件的“Close”(关闭)按钮:
好消息是,这对我们(或者跟我们协作的设计师)来说很容易修正。我们可以在App.xaml文件中的 "CloseButton" 样式中加一个ControlTemplate,加一些自定义的矢量形状来提供一个比较好看的关闭按钮(注:比我更称职的设计师大概还会加悬浮和动画行为到 矢量图像形状上去,让它更好看些):
重新运行我们的应用的话,按钮看上去象下图:
我们应用中我认为应该润色的第二个地方是ListBox的外圈界面。如果你仔细看的话,你可以看到Beta1版本中的ListBox有一个嵌套的边框,作为它的默认外观(注:我们还没最后决定要发布的默认皮肤,所以在最终版之前,这非常有可能会改变):
我们可以除去这个,通过定制它的控件模板来给与ListBox一个平的边框(flat border)。下面是一个以自定义模板样式化了的,有平的边框的ListBox :
注意我们是如何除去ListBox的边框控件的,我们只用了Silverlight中的<ScrollViewer>控件(该控件允许 其中任何内容做卷动),将一个<ItemsPresenter/>控件嵌入其中,该控件负责ListBox中实际条目的显示(它使用了我们在 第四部分中创建的 <DataTemplate> 来显示这些条目)。
下面是它现在给与我们的List更为平直的外观:
比较酷的是,为了做这些观感的改动,我们不用更改应用中的任何代码,或者修改实际的控件的XAML标识。这种代码、设计的分离能在 Silverlight和WPF应用中促进开发人员和设计师之间的流畅的工作流程。Expression Blend 和所有的 Expression Studio产品把这些控件设计功能提到了又一个高度,将提供方便这种定制的丰富的设计师工具集!