• 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方面的问题,可以给我留言一起探讨,感谢大家浏览
  • 相关阅读:
    preliminary->advanced exam selections
    Maven入门
    Ajax和Json
    过滤器和监听器
    JSTL标签库
    JSP与EL表达式
    dom4j与XML文档操作
    会话管理
    登录之验证码
    WEB之文件下载
  • 原文地址:https://www.cnblogs.com/stswordman/p/804872.html
Copyright © 2020-2023  润新知