WPF Unleashed Chapter 3:Important New Concepts in WPF ---Dependency Properties(Attached property)

Attached Properties
  
        Attached property是DP的一种特殊形态。它可将任意对象进行附加译。第一次听到这个名字可能会感到奇怪,但是WPF中的很多应用都会用到attached property。   
  
        在About dialog的例子中,比起在窗体级设置FontSize和FontStyle属性,在StackPanel控件里进行设置更加合适。但直接将这两个属性设置到StackPanel上是无效的,因为StackPanel自身并没有字体相关属性。所以必须使用FontSize和FontStyle的attached property,TextElement类定义了这两个属性。List3.5演示如如何使用attached property,图3.6为List3.5中代码的运行结果   
  
LISTING 3.5 The About Dialog with Font Properties Moved to the Inner StackPanel   
<Window xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”   
      Title=”About WPF Unleashed” SizeToContent=”WidthAndHeight”   
      Background=”OrangeRed”>   
      <StackPanel>   
            <Label FontWeight=”Bold” FontSize=”20” Foreground=”White”>   
                  WPF Unleashed (Version 3.0)   
            </Label>   
            <Label>© 2006 SAMS Publishing</Label>   
            <Label>Installed Chapters:</Label>   
            <ListBox>   
                  <ListBoxItem>Chapter 1</ListBoxItem>   
                  <ListBoxItem>Chapter 2</ListBoxItem>   
            </ListBox>   
            <StackPanel TextElement.FontSize=”30” TextElement.FontStyle=”Italic”   
                  Orientation=”Horizontal” HorizontalAlignment=”Center”>   
                  <Button MinWidth=”75” Margin=”10”>Help</Button>   
                  <Button MinWidth=”75” Margin=”10”>OK</Button>   
            </StackPanel>   
            <StatusBar>You have successfully registered this product.</StatusBar>   
      </StackPanel>   
</Window>   
  
  
        TextElement.FontSize 和TextElement.FontStyle 必须设置在StackPanel内部,因为StackPanel没有字体相关的属性。当XAML的解析器或编译器遇到这种语法时,会去调用TextElement(有时也叫做attachd property提供者)的静态方法SetFontSize和SetFontStyle。List3.5中XAML代码对应的等效c#代码为:    
  
      StackPanel panel = new StackPanel();   
      TextElement.SetFontSize(panel, 30);   
      TextElement.SetFontStyle(panel, FontStyles.Italic);   
      panel.Orientation = Orientation.Horizontal;   
      panel.HorizontalAlignment = HorizontalAlignment.Center;   
      Button helpButton = new Button();   
      helpButton.MinWidth = 75;   
      helpButton.Margin = new Thickness(10);   
      helpButton.Content = “Help”;   
      Button okButton = new Button();   
      okButton.MinWidth = 75;   
      okButton.Margin = new Thickness(10);   
      okButton.Content = “OK”;   
      panel.Children.Add(helpButton);   
      panel.Children.Add(okButton);    
         
        注意FontStyles.Italic, Orientation.Horizontal和HorizontalAlignment。Center 这些枚举类型在XAML中分别为Italic,Horizontal和Center。这些转换是由.NET Framework的EnumConverter的转换器完成的。    
  
        上面的c#代码显示了List3.5中的XAML完成的工作并不神奇。只是通过一个方法将元素和不相关的属性来联系到一起。 实际上,SetFontSize这类方法在内部都调用了相同的DependencyObject.SetValue方法:    
  
      public static void SetFontSize(DependencyObject element, double value)   
      {   
            element.SetValue(TextElement.FontSizeProperty, value);   
      }
 
        和SetValue方法类似,attached property也定义了GetXXX的静态方法(xxx是属性的名称),用来调用DependencyObject.GetValue方法:    
  
      public static double GetFontSize(DependencyObject element)   
      {   
            return (double)element.GetValue(TextElement.FontSizeProperty);   
      }    
  
    使用属性包装器时,一定不要在GetXXX和SetXXX方法里添加GetValue和SetValue以外的代码。
    
DIGGING DEEPER
  
Understanding the Attached Property Provider   
  
        List3.5中FontSize和FontStyle的attached property最令人困惑的就是这两个attached property既没有定义在Button上,也没有定义在那些含有FontSize和FontStyle的控件上。却是由看似毫不相关的TextElement类来定义的。TextElement.FontSizeProperty是独立于控件的FontSizeProperty之外的一个DP,那么attached proeprty是如何运转的呢?关键是attached property的注册方式。如果您查看了TextElement的源代码,会看到以下代码:    
  
      TextElement.FontSizeProperty = DependencyProperty.RegisterAttached(   
      “FontSize”, typeof(double), typeof(TextElement), new FrameworkPropertyMetadata(   
      SystemFonts.MessageFontSize, FrameworkPropertyMetadataOptions.Inherits |   
      FrameworkPropertyMetadataOptions.AffectsRender |   
      FrameworkPropertyMetadataOptions.AffectsMeasure),   
      new ValidateValueCallback(TextElement.IsValidFontSize));
  
 
      除了针对attach property的应用场景对元数据进行了优化之外,上面的代码里和之前为Button控件注册IsDefaultProperty是类似的。
         
        另一方面,WPF的控件本身并没有注册FontSize的DP。而是调TextElement类的AddOwner方法,获得了TextElement类的FontSize实例的副本:   
  
      Control.FontSizeProperty = TextElement.FontSizeProperty.AddOwner(   
      typeof(Control), new FrameworkPropertyMetadata(SystemFonts.MessageFontSize,   FrameworkPropertyMetadataOptions.Inherits));   
        
      所以,控件的FontSize,FontStyle,以及这些和字体相关的DP,都是来源与TextElement!   
     理解起来会有些混乱,幸运的是,在大多情况下,那些暴露attatched property(例如GetXXX和SetXXX方法)的类实际上就是那些使用DependencyProperty.RegisterAttached方法定义了DP的类。

  
        虽然About dialog例子中使用attached property是为了演示属性值继承,但实际上这个特性更多应用在用户界面元素的布局上。(实际上,attached property本身就是为了WPF的布局系统而设计的。)继承Panel类的各种布局类都定义了attached property,用于控制它们内部元素的摆放。这样,我们只需要在面板(panel)中定义各自的布局行为就可以了,而没必要将这些行为附加到他们的子元素上。attached property的另一个优点是,它增强了布局系统的扩展性:用户可以创建一个新型的Panel,并定义相应的attached property。第六章Layout with Panels和第十七章Layout with Custom Panels将详细介绍
  
 DIGGING DEEPER
  
Attached Properties as an Extensibility Mechanism   
  
        和以前的Windows Forms技术一样,WPF内的许多类都定义了Tag属性(类型为System.Object)。该属性可以存储任意的对象的实例。而attached property也有Tag类似功能,它可以将用户数据与继承自DependencyObject的对象联系在一起,并且功能更强大,更灵活。
  
        在XAML中使用attached property要用到静态的方法SetXXX,但您可以使用程序代码来避开这个麻烦,只需要直接调用DependencyObject类的SetValue方法就可以了。这样您就可以将任意DP作为attached property使用了。例如,下面的代码中,使用了SetValue将ListBox控件的IsTextSearchEnabled属性“系”到Button控件上,并分配了值:   
    
// Attach an unrelated property to a Button and set its value to true:   
okButton.SetValue(ListBox.IsTextSearchEnabledProperty, true);
  
  
        虽然看上去没什么意义,并且也没能给Button带来任何新的功能,但是您通过这种方式就可以随意消费这个属性值,这对于应用程序或组件来说很有用处。
        我们可以使用这种方式对元素进行扩展。例如,FrameworkElement类的Tag是个DP,所以可以将它附加到GeometryModel3D对象(该类是sealed的,并且没有Tag属性。第十二章3D Graphics将介绍)上:   
  
GeometryModel3D model = new GeometryModel3D();   
model.SetValue(FrameworkElement.TagProperty, “my custom data”);
  
  
这是WPF在不使用继承机制的情况对元素进行可扩展以一种方式。


                 下一章将介绍Routed Events
如果您有WPF方面的问题,可以给我留言一起探讨,感谢大家浏览
posted on 2007-07-04 09:29  stswordman  阅读(2629)  评论(2编辑  收藏  举报