Practice First

实践第一

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

Templates for uncommon controls

http://msdn.microsoft.com/en-us/magazine/cc135986.aspx

是该文章的读书摘记

 

以前的控件其外观代码和逻辑代码是帮定在一起的,如果你想改变一个控件的外观,你需要从那个控件的类派生,重写显示外观部分的代码。甚至有的时候,这样做也达不到你的目标。而在WPF中,逻辑和外观代码可以分离。利用Template可以很方便的改变控件的外观而不改变其功能。所有的WPF控件都有默认的 Template,你可以方便的替换鲜有的template而改Control的外观和显示。

 

Element Control的区别

WPFControl类从FrameworkElement类派生 ,像TextBlock, Image, Panel, Decorator等都从FrameworkElement直接派生,所以他们不是Control.

 

首先Control增加了很多属性,例如Foreground, Background 以及五个与Font有关的属性

其次Control增加了IsTabStopTabIndex属性,这使得Control可以相应Tab键的焦点切换,而FrameworkElement 则没有这个功能,一句话,FrameworkElement仅仅是为了外观,而 Control还增加了交互。

再者,Controltemplate, 可以被替换template而改变外观,template基本上就是代表控件外观的一颗视觉树,当然也包括响应属性变化和事件的一些triggers

 

 

所以如果你要创建自己的Control那么很重要的一点就是你要提供可替换的默认的template,尽管这不是必须的,但是这样做无疑会极大地改善你的Control的易用性。

要为你的Control DLL提供一个可被替换的默认的Template, 你必须遵守WPF的严格的规则:

1. 你的源代码项目下必须有一个Theme目录,包含一个叫General.xaml的文件

2. General.xaml是一个StyleResourceDictionary

3. Style中必须包含设置Template属性的Section

<RecourceDictonary>

               <Style TargetType="cc:CaladendarDay">

                              <Setter Property="Template">

                                             <Setter.Value>

                                                                           <ControlTemplate TargetType="..." >

                                                                                                         .....

                                                                           </ControlTemplate>

                                             </Setter.Value>

                              </Setter>

               </Style>

</ResourceDictonary>

4. 在你的控件类的静态构造函数中改变DefaultStyleKeyProperty属性的默认值:

 

 

 

 

一般来说你设计一个控件,会从Control派生,并且增加一些属性。那么这里最好背后都是用DependencyProprty, 以使得这些属性可以Data Binding,并且利用Routed Event机制,在你的属性改变的时候,其他相关的对象得到通知。

 

如果你需要属性已经在其他类里面定义过了,不要重新定义它,需要AddOwner

使用DependencyProperty.OverrideMetaData可以用来改变从父类Control继承过来的Dependency属性的默认值,以及注册一个回调函数在属性改变的时候被0调用。

 

 

 覆盖OnApplyTemplate函数,以便检验Template的合法性以及建立与代码与template的连接,因为你或许需要Template中有指定的part, 例如ItemsControl都有一个叫PART_Panelpanal

 

template中使用TemplateBinding绑定到那些新定义的DependencyProperty, 这样这些属性的改变就会反映到控件的外观上。对于那些可以通过视觉树从Control类继承的属性则不需要做任何处理,会自动应用到控件的外观上。例如 Foreground以及5个与Font相关的属性就会自动的应用于控件的外观,而不需要我们在Template中使用TemplateBinding来绑定。

 

Template中应该尽量少的使用硬编码来设置一些属性的值,这样使用控件的人如果需要修改这些默认值就会很麻烦。一种可行的方法是,直接在Style中设置这些值,而不是在Template中设置这些值。这样控件的使用者就可以很方便的修改这些值。

 

如果你的代码会假定Template 中必须有某些类型的部件,那么最好用TemplatePart性在你的Control的派生类上来标明。

[TemplatePart(Name="PART_Panel", Type=TypeOf(Panel))]

public class CalandarDay: Control

{ ....

}

 

你的Control派生类最好也可以暴露出一些RoutedCommand对象,使得 Template可以帮定以执行一些功能

public static readonly RoutedCommand NextMonthCoommand = new RoutedCommand("NextMonth", typeof(CalendarMonth));

其实只有少数WPF控件可以绑定到RoutedCommand, ButtonBase, MenuItem, HyperLink等。

 

posted on 2010-03-13 07:09  caoshenghe  阅读(431)  评论(0编辑  收藏  举报