在ASP.NET中,我们看到的Control都是通过浏览器渲染Html产生的,说实话刚做Web的时候,需要掌握很多的知识,比如Js,Css,Ajax,这些需要学的东西
很多,而且每一个都几乎是一个全新的知识,再加上自己没多少艺术细胞,所以做出来的效果总是很丑陋,连自己都看不下去,更何况别人了。所以当初自己刚接触
Silverlight时,就立刻被其绚丽的UI震撼了。
最近因为工作需要,研究了一下Silverlight Toolkit中的部分控件源码,感觉收获颇多,关于Silverlight自定义控件,我觉得需要对Silverlight的基本概念掌握到一
定的火候才行,因为如果想设计好一个自定义控件,就要熟悉依赖属性,动画,UIElement,Style,这些几乎都是Silverlight的精华所在。
在Silverlight中可以通过XAML控件元素包含的属性进行外观的设置,但是这些更改其实很有限的,如果通过更改这些属性无法达到的自己想要的效果,就可以使用
ControlTemlpate,其指定了控件的可视结构和可视行为,可以在不更改控件现有的功能情况下更改外观。
Control类中定义了Template的属性,ControlTemlpate可以应用于从Control继承的元素,但是UserControl除外
对XAML元素控件中定义ControlTemplate主要有3种方式,方法与应用Style是一样的
内联定义:
<ToolTip><ToolTip.Template><ControlTemplate TargetType="ToolTip">...</ControlTemplate></ToolTip.Template></ToolTip>
资源引用:
<UserControl.Resources><ControlTemplate x:Key="toolTip" TargetType="ToolTip">...</ControlTemplate></UserControl.Resources><Grid x:Name="LayoutRoot" Background="White"><ToolTip><ToolTip.Template><StaticResource ResourceKey="toolTip"></StaticResource></ToolTip.Template></ToolTip></Grid>
样式引用:
<UserControl.Resources><Style TargetType="ToolTip" x:Key="toolTip"><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="ToolTip">...</ControlTemplate></Setter.Value></Setter></Style></UserControl.Resources><ToolTip Style="{StaticResource toolTip}" ></ToolTip>
使用Style是ControlTemplate使用比较常见的方式,其实就是设置Template属性。在Silverlight中使用ControlTemplate时,可以重新组合
FrameworkElement对象来更改可视结构,但是必须唯一的FrameworkElement作为其根元素,看一看Tooltip默认的ControlTemplate
<ControlTemplate TargetType="ToolTip"><Border x:Name="Root" CornerRadius="2" BorderThickness="{TemplateBinding BorderThickness}" Background="#FFFFFFFF" BorderBrush="{TemplateBinding BorderBrush}"><Border BorderBrush="#FFFFFFFF" BorderThickness="1" CornerRadius="1" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}"><Border.Resources><Storyboard x:Key="Visible State"/><Storyboard x:Key="Normal State"/></Border.Resources><ContentPresenterContent="{TemplateBinding Content}"ContentTemplate="{TemplateBinding ContentTemplate}"Cursor="{TemplateBinding Cursor}"Margin="{TemplateBinding Padding}"/></Border></ControlTemplate>
这里名为Root的Border作为ControlTemplate的根元素,并且使用ContentPresent用于显示任何类型的对象。
ContentPresent:
如果ContentPresent对象是存在于ContentControl的ControlTemplate中,那么就ContentPresent会自动绑定到Content与ContentTemplate,比如
Tooltip是继承自ContentControl的:
那么我们上面的ContentPresent中就可以省略Content与ContentTemplate的绑定,可以直接写成
<ContentPresenter Cursor="{TemplateBinding Cursor}" Margin="{TemplateBinding Padding}"/>
同样的,如果我们使用位于ItemsControl的ControlTemplate 中的 ItemsPresenter ,其将自动绑定到 Items和ItemsPresenter属性。
TemplateBinding
TemplateBinding将ControlTemplate 中元素的属性绑定到由控件定义的公共属性。创建好一个ControlTemplate后,如果在ContentPresenter中,设置了一
个值后,那么你设置控件的属性是不会产生任何影响的。
<ContentPresenter Cursor="Hand" Margin="{TemplateBinding Padding}"/>
这里我们将上面的ControlPresenter中的Cursor设置为Hand,那么对应用了该ControlTemplate的ToolTip,无论设置Cursor为何值,移到内容显示区域时
显示出来的图标都是Hand。
在Control类中定义了一些可以由ControlTemlate使用的可视属性
尽管我们在上面的ContentTemplate中并没有显示的设置Foreground,但是当我们改变Tooltip的Foreground的值时,可以看到效果有所变化,因为
Foreground是继承而来的,尽管并没有使用{TemplateBinding Foreground}
从图中也可以看出来ControlTemplate可以通过两种方式使用这些属性,除了这些可视属性,还可以继承父元素的DataContext,Language,TextDercoration。
VisualStateManager
上面仅仅是讲ControlTemplate使得XAML元素的外观比较灵活的方式呈现,Silverlight中每个控件有默认的视觉效果,并且可以改变默认效果,
这主要应用了VisualStateManager特性
VisualState 对象可指定控件在处于特定状态时的外观
VisualState 中包含了Storyboard,可用于更改ControlTemplate中元素的外观,控件进入 VisualState.Name 属性指定的状态时,动画开始工作,
控件退出该状态时,动画停止。
XAML一般如下定义:
<vsm:VisualState x:Name="Closed">
<Storyboard><ColorAnimation ...></ColorAnimation></Storyboard></vsm:VisualState>
上面的表示的是ToolTip关闭时的动画, VisualState的Name要与ToolTip上的TemplateVisualStateAttribute相匹配
VisualState可被添加至VisualStateGroup 对象中
<VisualStateGroup x:Name="OpenStates"><vsm:VisualState x:Name="Closed"><Storyboard><ColorAnimation ...></ColorAnimation></Storyboard></vsm:VisualState><vsm:VisualState x:Name="Open"><Storyboard><ColorAnimation ...></ColorAnimation></Storyboard></vsm:VisualState></VisualStateGroup>
VisualStateGroup 可被添加到 VisualStateManager.VisualStateGroups这个附加属性中,其必须在ControlTemplate中的根FrameworkElement进行设置。
<ControlTemplate TargetType="ToolTip"><Border><VisualStateManager.VisualStateGroups>...</VisualStateManager.VisualStateGroups></Border></ControlTemplate>
TemplateVisualStateAttribute
控件状态都是由位于该控件的类定义中的 TemplateVisualStateAttribute 指定的,该特性指定了状态的名称和状态所属的状态组的名称。
TemplateVisualState的GroupName指定了状态组,同一状态组中的状态是互斥的,控件始终只能处于每组状态中的一种。除了该特性外,如果看看Toolkit的源码,
还会看见常用的其它特性:TemplatePartAttribute,StyleTypedPropertyAttribute ,这里暂不过多的扩展了。
其实我觉得看了点入门的东西后,学习Silverlight最好的文档就是SDK里的脱机文档了,发现文章有点长了,果断收笔。