WPF依赖属性
理解依赖属性依赖属性支持的特征包括:动画、数据绑定、样式。 可以分配WPF元素的属性大部分都是依赖属性。 依赖属性和常规属性的用法相同。 WPF设计了依赖属性支持其特有的动态特性,并且不干扰其他系统的.net代码。 定义依赖属性public class FrameworkElement: UIElement,... { public static readonly DependencyProperty MarginProperty; ... } 依赖属性的定义是静态属性。这是为了使其一直可用。在类内的实例之间、甚至在不同的类之间如WPF元素共享。 根据命名约定,依赖属性定义时名字带有Property后缀。使用依赖属性可以省略Property后缀。 依赖属性是只读的,只能在类的静态构造函数中设置,见下节。 注册依赖属性依赖属性不能被直接实例化,在创造后不能被修改,也就是其不可变的。所以,依赖属性类没有公有的构造函数,并且定义为readonly。其构造必须在类的静态函数中,通过静态的DependencyProperty.Register()方法设置。 static FrameworkElement() { var metadata = new FrameworkPropertyMetadata( new Thickness(),FrameworkPropertyMetadataOptions.AffectsMeasure); MarginProperty = DependencyProperty.Register("Margin",typeof(Thickness),typeof(FrameworkElement),metadata,new ValidateValueCallback(FrameworkElement.IsMarginValid)); ... } FrameworkPropertyMetadata类用于设置依赖属性支持什么功能。 Register()方法的参数分别为:属性名称、属性类型、所属类的类型、额外的属性设置(可选)、执行验证的回调(可选)。 两个可选属性值得研究。FrameworkPropertyMetadata的详细描述见95页。 包裹依赖属性调用定义在DependencyObject中的SetValue()和GetValue()方法包裹属性。 public Thickness Margin { set { SetValue(MarginProperty,value); } get { return (Thickness)GetValue(MarginProperty); } } 仅此而已,不应该再添加额外的代码如验证输入值、引发事件等等。 验证输入值应使用DependencyProperty.ValidateValueCallback。 引发事件应使用FrameworkPropertyMetadata.PropertyChangedCallback 。 现在可以使用属性了: myElement.Margin = new Thickness(5); 晚些时候,可能希望移除局部值设置,仿佛你从未设置它。 myElement.ClearValue(FrameworkElement.MarginProperty); 使用依赖属性依赖属性支持两个关键的特征:改变通知和动态值求解。 如果希望反应属性改变,有二个选择:属性值绑定、或触发器。 动态值求解,依赖属性根据下列因素求基础值(后来者赢):
WPF通过4个步骤求得属性值:
共享依赖属性即使类的层次架构互相独立,一些类共享同样的依赖属性。比如,TextBlock.FontFamily和Control.FontFamily都指向相同的依赖属性TextElement.FontFamilyProperty。TextBlock和Control类知识简单的重用它,依靠的是DependencyProperty.AddOwner()方法: TextBlock.FontFamilyProperty = TextElement.FontFamilyProperty.AddOwner(typeof(TextBlock)); 自定义类的时候可以使用这个技术。 重用依赖属性会导致一些奇怪的副作用。使用样式时常会出现,比如,你使用样式设置TextBlock.FontFamily属性,Control.FontFamily属性也会被影响。 附加属性相比普通的依赖属性,注册一个附加属性使用RegisterAttached()方法代替Register()方法。如: var metadata = new FrameworkPropertyMetadata( 0,new PropertyChangedCallback(Grid.OnCellAttachedPropertyChanged)); Grid.RowProperty = DependencyProperty.RegisterAttached("Row",typeof(int),typeof(Grid),new ValidateValueCallback(Grid.IsIntValueNotNegative)); 当定义附加属性时,不需要.net属性包裹器。它需要一对静态方法,用来设置或获取属性值。如: public static int GetRow(UIElement element) { if (element == null) { throw new ArgumentNullException(...); } return (int)element.GetValue(Grid.RowProperty); } public static void SetRow(UIElement element,int value) { if (element == null) { throw new ArgumentNullException(...); } element.SetValue(Grid.RowProperty,value); } 用法: Grid.SetRow(txtElement,0); 另一个用法: txtElement.SetValue(Grid.RowProperty,0); 属性验证WPF提供两条路阻止无效值:ValidateValueCallback、CoerceValueCallback。 当设置一个依赖属性时,依次经过:CoerceValueCallback、ValidateValueCallback、PropertyChangedCallback Validation回调相当于正常属性的set部分中的验证。 其签名为接受一个object输入参数,返回boolean值。返回值为真表示接受,为假表示拒绝。 private static bool IsMarginValid(object value) { Thickness thickness1 = (Thickness) value; return thickness1.IsValid(true,false,true,false); } 有一个限制,它是一个静态方法,不能访问正被验证的对象,不能使用对象中的其他属性。 Coercion回调用于验证互相关联的属性 private static object CoerceMaximum(DependencyObject d,object value) { RangeBase base1 = (RangeBase)d; if (((double) value) < base1.Minimum) { return base1.Minimum; } return value; } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |