依赖属性 依赖属性回调方法与参数 具有依赖属性的类必须继承自DependencyObject
,定义依赖属性要有2个步骤
1 2 3 4 5 6 7 8 9 public int Name{ get { return (int )GetValue(NameProperty); } set { SetValue(NameProperty, value ); } } public static readonly DependencyProperty NameProperty = DependencyProperty.Register("Name" , typeof (int ), typeof (ownerclass), new PropertyMetadata(0 ));
注册依赖属性第一个参数表示对应包装器的名称,第二个为属性类型,第3个为属于哪个类。
本文着重讲解第四个之后的参数
public static DependencyProperty Register(string name, Type propertyType, Type ownerType, PropertyMetadata typeMetadata, ValidateValueCallback validateValueCallback);
public PropertyMetadata(object defaultValue, PropertyChangedCallback propertyChangedCallback, CoerceValueCallback coerceValueCallback);
参数 备注 defaultValue 默认参数 propertyChangedCallback 属性变化回调函数 coerceValueCallback 强制回调函数
第五个参数ValidateValueCallback public delegate bool ValidateValueCallback(object value);
数据验证回调函数
使用 1 2 3 4 5 6 7 8 9 10 11 12 ValueProperty = DependencyProperty.Register( "Value" , typeof (int ), typeof (MainWindow), new PropertyMetadata( 1 , new PropertyChangedCallback(OnPropertyChanged), new CoerceValueCallback(OnCoerceValueCallback) ), new ValidateValueCallback(OnValidateValueCallBack) );
属性变化回调 1 2 3 4 5 6 7 8 9 static void OnPropertyChanged (DependencyObject d, DependencyPropertyChangedEventArgs e ){ }
验证回调 先调用验证回调,验证通过后,才调用属性变化回调。但是如果新旧值相同时,不触发属性变化回调
1 2 3 4 5 6 7 8 9 10 11 12 13 static bool OnValidateValueCallBack (object obj ){ return true ; }
强制回调 首先,走验证回调,再走强制回调,再走属性变化回调
1 2 3 4 5 6 7 8 9 10 11 12 static object OnCoerceValueCallback (DependencyObject d, object obj ){ if (int .Parse(obj.ToString()) > 1000 ) return 1000 ; return obj; }
有时会使用FrameworkPropertyMetadata类作为DependencyProperty.Register
的第4个参数,该类继承自PropertyMetadata
1 public FrameworkPropertyMetadata (object defaultValue, FrameworkPropertyMetadataOptions flags, PropertyChangedCallback propertyChangedCallback, CoerceValueCallback coerceValueCallback, bool isAnimationProhibited, UpdateSourceTrigger defaultUpdateSourceTrigger ) ;
FrameworkPropertyMetadataOptions:指定了与布局或者数据绑定等依赖项属性的交互特征
isAnimationProhibited:这个属性能否用于动画 defaultUpdateSourceTrigger:何时更新绑定元数据
属性继承 如果在<Window>
定义font=30,则在Window中的控件字体都会默认实现font=30,这是如何实现的呢?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 class Control1 :ContentControl { public int Value { get { return (int )GetValue(ValueProperty); } set { SetValue(ValueProperty, value ); } } public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value" , typeof (int ), typeof (Control1), new FrameworkPropertyMetadata(0 , FrameworkPropertyMetadataOptions.Inherits)); } class Control2 : ContentControl { public int Value { get { return (int )GetValue(ValueProperty); } set { SetValue(ValueProperty, value ); } } public static readonly DependencyProperty ValueProperty = Control1.ValueProperty.AddOwner(typeof (Control2), new FrameworkPropertyMetadata(0 , FrameworkPropertyMetadataOptions.Inherits)); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <StackPanel > <local:Control1 x:Name ="c1_1" Value ="10" > <local:Control2 x:Name ="c1_2" /> </local:Control1 > <TextBlock Text ="{Binding Path=Value,ElementName=c1_2}" /> <local:Control2 x:Name ="c2_2" Value ="10" > <local:Control1 x:Name ="c2_1" /> </local:Control2 > <TextBlock Text ="{Binding Path=Value,ElementName=c2_1}" /> </StackPanel >
依赖附加属性 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class Control3 { public static string GetPasswordValue (DependencyObject obj ) { return (string )obj.GetValue(PasswordValueProperty); } public static void SetPasswordValue (DependencyObject obj, string value ) { obj.SetValue(PasswordValueProperty, value ); } public static readonly DependencyProperty PasswordValueProperty = DependencyProperty.RegisterAttached("PasswordValue" , typeof (string ), typeof (Control3), new PropertyMetadata("" , new PropertyChangedCallback(OnPasswordValueChanged))); private static void OnPasswordValueChanged (DependencyObject d, DependencyPropertyChangedEventArgs e ) { (d as PasswordBox).Password = e.NewValue.ToString(); } }
1 2 3 4 5 6 <Window.Resources > <sys:String x:Key ="pwd" > 123456</sys:String > </Window.Resources > <StackPanel > <PasswordBox Password ="" local:Control3.PasswordValue ="{Binding Source={StaticResource pwd}}" /> </StackPanel >
PasswordBox中的Password属性是一个普通的string类型属性,无法使用Binding进行绑定,所以使用附加属性
类型转换 用于将XAML中输入的属性值(字符串)转换成对应的对象
1.自定义对象类
1 2 3 4 5 6 [TypeConverter(typeof(CPTypeConverter)) ] public class ContorlProperty { public double Width { get ; set ; } public double Height { get ; set ; } }
使用ContorlProperty类型作为属性 1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class Control4 :ContentControl { public ContorlProperty MyProperty { get { return (ContorlProperty)GetValue(MyPropertyProperty); } set { SetValue(MyPropertyProperty, value ); } } public static readonly DependencyProperty MyPropertyProperty = DependencyProperty.Register("MyProperty" , typeof (ContorlProperty), typeof (Control4), new PropertyMetadata(null )); }
定义转换 1 2 3 4 5 6 7 8 9 10 11 public class CPTypeConverter : TypeConverter { public override object ? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value ) { var temp = value .ToString().Split(',' ); double v1 = double .Parse(temp[0 ]); double v2 = double .Parse(temp[1 ]); return new ContorlProperty() { Width = v1, Height = v2 }; } }
完成上述步骤后可以这样使用 1 2 3 <StackPanel > <local:Control4 MyProperty ="100,60" /> </StackPanel >
绑定表达式 如果要做数据变化通知,推荐使用INotifyPropertyChanged,而不是使用依赖属性,原因:
类可以不继承自DependencyObject 依赖属性是静态的,占用资源更大