理解依赖属性
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; }
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。