所有的DependencyProperty成员都是公共类型和静态类型的(public and Static),并且要以“Property”字符串结尾
public static readonly DependencyProperty xxxProperty;
DP通常会用DependencyProperty类的静态方法Register方法创建。 Register方法需要以下参数:DP的名称,属性类型,该属性类型的所有者类型。 Register还有一些重载方法,您可以将一些元数据传递给这些方法。这些元数据可以决定属性如何被WPF对待,是否当属性值改变时进行回调,强制限定属性值或者验证属性值。为DP设置了默认值,并且设置了变更通知(change notifications)的委托。
xxxProperty=DependencyProperty.Register("property name", typeof(int), typeof(own type), new UIPropertyMetadata(0, XXXChanged));
xxxProperty=DependencyProperty.Register("property name", typeof(int), typeof(own type), new UIPropertyMetadata(false,new PropertyChangedCallback(XXXChanged)));
public static void XXXChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { }
实现了自己的访问器(accessors)
public type XXX { get { return (type)GetValue(xxxProperty); } set { SetValue(xxxProperty, value); } }
XAML编译器在编译时会用到属性包装器,而在运行时WPF会直接调用底层的GetValue和SetValue方法。所以为了保持XAML代码与程序代码之间的一致,在属性包装器的GetValue和SetValue方法中绝对不能添加任何逻辑代码。如果您的确需要添加一些逻辑代码,可以写在变更通知的回调方法中。所有的WPF内置的属性包装器都遵循了这一原则。
xxxProperty是个静态成员(而不是实例成员),所以DP节省了相对于传统.NET属性的每一个实例的内存。如果所有的WPF控件都使用实例属性(像大多数的.NET属性那样),那么就会消耗掉数量可观的内存,
DP对.NET属性上的增强功能
Change notification
Property value inheritance
Support for multiple providers
Change notification
属性触发器(property trigger)
您希望鼠标悬浮在按钮上时,按钮的文字变成蓝色。如果不使用属性触发器,您可以在按钮的MouseEnter事件和MouseLeave事件中进行处理: <Button MouseEnter=”Button_MouseEnter” MouseLeave=”Button_MouseLeave” MinWidth=”75” Margin=”10”>Help</Button> <Button MouseEnter=”Button_MouseEnter” MouseLeave=”Button_MouseLeave” MinWidth=”75” Margin=”10”>OK</Button>
使用c#实现两个事件处理函数: // Change the foreground to blue when the mouse enters the button void Button_MouseEnter(object sender, MouseEventArgs e) { Button b = sender as Button; if (b != null) b.Foreground = Brushes.Blue; } // Restore the foreground to black when the mouse exits the button void Button_MouseLeave(object sender, MouseEventArgs e) { Button b = sender as Button; if (b != null) b.Foreground = Brushes.Black; }
有了属性触发器,您就可以在XAML中实现相同的功能了,代码相当简洁: <Trigger Property=”IsMouseOver” Value=”True”> <Setter Property=”Foreground” Value=”Blue”/> </Trigger>
这个属性触发器作用与Button的IsMouseOver属性。当MouseEnter触发的那一刻,属性值为True,MouseLeave事件触发时变为false。注意,您不需要关心IsMouseOver变为false时Foreground属性是否会变回黑色,这个操作由WPF自动完成。 唯一的窍门是如何将属性触发器应用到Button中。不幸的是,由于3.0版本中WPF的人为限制,您无法将属性触发器直接应用到元素中。必须将它放到Style对象内,4.0中,是否可以直接应用?要调查? <Button MinWidth=”75” Margin=”10”> <Button.Style> <Style TargetType=”{x:Type Button}”> <Style.Triggers> <Trigger Property=”IsMouseOver” Value=”True”> <Setter Property=”Foreground” Value=”Blue”/> </Trigger> </Style.Triggers> </Style> </Button.Style> OK </Button> WPF一共支持三种触发器。 ・属性触发器 ・数据触发器(data trigger) ・事件触发器(event trigger)
Property Value Inheritance
并不是传统面向对象里的继承,而是指属性值会沿着元素树向下传
Support for Multiple Providers
下面一时还看不懂。
--------------------------------------
WPF包含了很多强大的机制(指属性提供者,译者注),可以独立地设置DP的值。如果没有明确的机制去处理这些迥然不同的属性值提供者,那么系统会变得混乱,属性的值也会不能预测。从这些提供者的名字可以看出,dp的值会按照一定顺序设置。 图3.5 展示WPF为dp赋值的5个步骤。DP内置的变更通知特性使得该过程可以自动完成。
Step 1: 确定基础值(Determine Base Value) 大多数属性提供这都会影响基础值。下面列出了8个提供者,按照优先级从高到低排列: 1. Local value 2. Style triggers 3. Template triggers 4. Style setters 5. Theme style triggers 6. Theme style setters 7. Property value inheritance 8. Default value 您之前已经看到了一些属性值提供者,例如之前的 属性值继承就是其中之一。Local Value可以用DependencyObject.SetValue进行赋值,但典型的赋值手段一般是在XAML或程序代码中使用属性进行赋值(因为dp实现了属性,例如之前的Button.IsDefault属性)。Default value是指dp注册时设置的默认值,它的优先级是最低的。其它的提供者我们将在第十章介绍。 提供者优先级的顺序解释了List3.4中StatusBar控件的FontSize和FontStyle不会受到属性值继承的影响原因。系统设置属于Theme Style setters,其优先级要高于Property value inheritance。所以您可以为StatusBar设置优先级更高的提供者,例如Local value。 Step 2: 求值(Evaluate) 如果step 1中的值是一个表达式(继承自System.Windows.Expression类的对象),WPF将会执行求职步骤,将表达式转换成具体的结果。在3.0版本的wpf中,只有在使用动态资源(dynamic resources)或数据绑定时,表达式才是有效的。以后的版本中会添加更多的表达式。 Step 3: 应用动画(Apply Animations) 如果元素的一个或者多个动画正在运行,这些动画会改变或完全替换相应的属性的值。所以,动画(第十三章)可以改变所有提供者设置的值--甚至是local value提供者。它对于WPF的新手来说是个学习过程中的绊脚石 Step 4: 强制(Coerce) 提供者设置完值以后,WPF得到了属性值的最终结果,并将它传递给CoerceValueCallback委托(如果在注册dp时注册了该委托)。这个委托会根据用户逻辑返回一个新值。例如WPF的ProgressBar就是用这个委托将dp的值约束在Minimun和Maximum之间 Step 5: 验证(Validate) 最后,第四步得到的值会传递给ValidateValueCallback。这个委托会返回一个布尔类型:通过验证返回true,否则返回false。如果返回false,系统会引发异常,终止整个过程 T I P
