Silverlight中的ControlTemplate

      在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除外

    image

  对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>
                          <ContentPresenter
                              Content="{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的:

      image

   那么我们上面的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使用的可视属性        image

         尽管我们在上面的ContentTemplate中并没有显示的设置Foreground,但是当我们改变Tooltip的Foreground的值时,可以看到效果有所变化,因为

Foreground是继承而来的,尽管并没有使用{TemplateBinding Foreground}

         从图中也可以看出来ControlTemplate可以通过两种方式使用这些属性,除了这些可视属性,还可以继承父元素的DataContext,Language,TextDercoration。

  VisualStateManager

        上面仅仅是讲ControlTemplate使得XAML元素的外观比较灵活的方式呈现,Silverlight中每个控件有默认的视觉效果,并且可以改变默认效果,

这主要应用了VisualStateManager特性

        VisualState 对象可指定控件在处于特定状态时的外观

image        VisualState 中包含了Storyboard,可用于更改ControlTemplate中元素的外观,控件进入 VisualState.Name 属性指定的状态时,动画开始工作,

控件退出该状态时,动画停止。

        XAML一般如下定义:

        <vsm:VisualState x:Name="Closed">
            <Storyboard>
            <ColorAnimation ...></ColorAnimation>
            </Storyboard>
        </vsm:VisualState>

      上面的表示的是ToolTip关闭时的动画,  VisualState的Name要与ToolTip上的TemplateVisualStateAttribute相匹配

image     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里的脱机文档了,发现文章有点长了,果断收笔。

posted @ 2010-11-29 17:09  ringgo  阅读(6151)  评论(8编辑  收藏  举报