依赖属性的意义和作用
- 核心模块
- 内存共享,节省空间
- 数据绑定、样式、模板、动画。。。。
- 如果没有依赖属性,这个框架就是一个控件框架 相当于Winform
依赖属性的基本定义
基本过程:声明、注册、包装
在需要写依赖属性的类中,继承DependencyObject,或者DependencyObject以下的类都行:
声明
public static readonly DependencyProperty ValueProperty;
注意:
声名 DependencyProperty
约定:名字命名为:名字+Property
readonly 只能被赋值一次,不能被二次修改
注意:readonly这里的只读是限制注册的,不包含里面的值,所以可以动态赋值SetValue
注册
基本的三个参数: 属性名称、属性类型、所属类型(所使用的类的名称)
ValueProperty = DependencyProperty.Register("Value",typeof(double),typeof(DependencyPropertyStudy));
包装
将依赖属性,包装成普通属性,修改和创建
必须继承DependencyObject及以上的类,才可以写GetValue和SetValue:
public double Value{get { return (double)GetValue(ValueProperty); }set{SetValue(ValueProperty, value);}}
代码片段:propdp
输入propdp + tab 自动生成
和上面注册是一样的,不过多了一个默认值(PropertyMetadata),加粗的部分是需要自定义的,根据自己的需求来。
public int MyProperty{get { return (int)GetValue(MyPropertyProperty); }set { SetValue(MyPropertyProperty, value); }}// Using a DependencyProperty as the backing store for MyProperty. This enables animation, styling, binding, etc...public static readonly DependencyProperty MyPropertyProperty =DependencyProperty.Register("MyProperty", typeof(int), typeof(ownerclass), new PropertyMetadata(0));
依赖属性的主要参数与回调参数
默认值
ValueProperty = DependencyProperty.Register("Value",typeof(double),typeof(DependencyPropertyStudy));
属性值变化回调:
ValueProperty = DependencyProperty.Register("Value",typeof(double),typeof(DependencyPropertyStudy),new PropertyMetadata(1d,new PropertyChangedCallback(OnValueChanged)));// 属性值变化回调参数
private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{// 静态回调 本方法体的非静态方法(d as DependencyPropertyStudy).Refresh();
}
属性值变化的时候,进入此回调函数e.NewValue 将被修改。
如果调用成功 这里将之后对应的依赖值发生了变化
当两次值一样的时候,不触发
验证回调:
ValueProperty = DependencyProperty.Register("Value",typeof(double),typeof(DependencyPropertyStudy),new PropertyMetadata(1d),new ValidateValueCallback(OnValueValidation));/// <summary>
/// 对数据的判断结果 编译能触发限制报错信息
/// 需要强制回调的时候,就不要给验证信息False 否则不走强制回调
/// </summary>
/// <param name="v">依赖属性所接受到的最新的值</param>
/// <returns>对数据的判断结果</returns>
private static bool OnValueValidation(object v)
{//if((double)v > 2000d)// return false;return true;
}
强制回调
ValueProperty = DependencyProperty.Register("Value",typeof(double),typeof(DependencyPropertyStudy),new PropertyMetadata(1d,new PropertyChangedCallback(OnValueChanged),new CoerceValueCallback(OnValueCoerce)));// 强制回调参数
// 如果值超限,可以强制改回需要的值范围private static object OnValueCoerce(DependencyObject d, object v){if ((double)v > 255d)return 255d;if ((double)v < 0d)return 0d;return v;}
完整代码:三个回调一起
ValueProperty = DependencyProperty.Register("Value",typeof(double),typeof(DependencyPropertyStudy),new PropertyMetadata(1d,new PropertyChangedCallback(OnValueChanged),new CoerceValueCallback(OnValueCoerce)),new ValidateValueCallback(OnValueValidation));// 属性值变化回调:处理的是监听属性值的变化private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e){// 如果调用成功 这里将之后对应的依赖值发生了变化// 当两次值一样的时候,不触发// 静态回调 本方法体的非静态方法(d as DependencyPropertyStudy).Refresh();}/// <summary>/// 对数据的判断结果 编译能触发限制报错信息/// </summary>/// <param name="v">依赖属性所接受到的最新的值</param>/// <returns>对数据的判断结果</returns>private static bool OnValueValidation(object v){//if((double)v > 2000d)// return false;return true;}// 强制回调参数private static object OnValueCoerce(DependencyObject d, object v){if ((double)v > 255d)return 255d;if ((double)v < 0d)return 0d;return v;}
执行顺序:
验证回调(首先给个默认值验证) --> 加载方法(load) --> 强制回调 --> 属性变化回调 --> 验证回调
元数据:FrameworkPropertyMetadataOptions
public double ColumnSpace{get { return (double)GetValue(ColumnSpaceProperty); }set { SetValue(ColumnSpaceProperty, value); }}// Using a DependencyProperty as the backing store for ColumnSpace. This enables animation, styling, binding, etc...public static readonly DependencyProperty ColumnSpaceProperty =DependencyProperty.Register("ColumnSpace",typeof(double), typeof(XHPanel),//new PropertyMetadata(0d,new PropertyChangedCallback(OnColumnSpaceChanged))// AffectsArrange: 影响排列 AffectsMeasure:影响测量 // 如果有多个用"|"分开new FrameworkPropertyMetadata(0d,FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure));
此元数据使用在自定义控件的时候,修改属性时刷新UI是使用
扩展:FrameworkPropertyMetadataOptions 的属性:
None:未指定任何选项;依赖属性使用 WPF 属性系统的默认行为。
AffectsMeasure:更改此依赖属性的值会影响布局组合的测量过程。
AffectsArrange:更改此依赖属性的值会影响布局组合的排列过程。
AffectsParentMeasure:更改此依赖属性的值会影响父元素上的测量过程。
AffectsParentArrange:更改此依赖属性的值会影响父元素上的排列过程。
AffectsRender:更改此依赖属性的值会影响呈现或布局组合的某一方面(不是测量或排列过程)。
Inherits:此依赖属性的值将由子元素继承。
OverridesInheritanceBehavior:此依赖属性的值跨越分隔的树以实现属性值继承。
NotDataBindable:不允许将数据绑定到此依赖属性。
BindsTwoWayByDefault:此依赖属性上的数据绑定的 System.Windows.Data.BindingMode 默认为 System.Windows.Data.BindingMode.TwoWay。
Journal:此依赖属性的值应由日记记录进程或在由统一资源标识符 (URI) 导航时进行保存或存储。
SubPropertiesDoNotAffectRender:此依赖属性值上的子属性不会影响呈现的任何方面。
依赖属性的继承
允许元素树中的子元素从最近的父元素获取特定属性的值
由于父元素也可能通过属性值继承获得其属性值,因此系统可能递归回页面根
父亲依赖属性代码:
public int Test{get { return (int)GetValue(TestProperty); }set { SetValue(TestProperty, value); }
}// Using a DependencyProperty as the backing store for MyProperty. This enables animation, styling, binding, etc...
public static readonly DependencyProperty TestProperty =DependencyProperty.Register("Test", typeof(int), typeof(XHPanel),new FrameworkPropertyMetadata(0, FrameworkPropertyMetadataOptions.Inherits));
子类继承代码:
关键字:父类.依赖属性.AddOwner(类型,默认值)
public int Test{get { return (int)GetValue(TestProperty); }set { SetValue(TestProperty, value); }}// 依赖属性的继承 继承于XHPanel 的 TestProperty// 允许元素树中的子元素从最近的父元素获取特定属性的值// 由于父元素也可以通过属性值继承获得其属性值,因此系统可能地归回页面根public static readonly DependencyProperty TestProperty =XHPanel.TestProperty.AddOwner(typeof(DependencyPropertyStudy),new FrameworkPropertyMetadata(0, FrameworkPropertyMetadataOptions.Inherits));
演示:XAML代码
<local:XHPanel Test="12" ColumnSpace="20" RowSpace="20" Visibility="Collapsed"><local:DependencyPropertyStudy x:Name="dps" />
</local:XHPanel>
<Button Width="200" Height="30"Content="测试依赖属性继承" FontSize="20" Click="Button_Click"/>
按钮事件代码:
private void Button_Click(object sender, RoutedEventArgs e)
{// 此时子没设置Test 属性,看是否可以弹出继承父的TestMessageBox.Show(this.dps.Test.ToString());
}
效果:
以上就是所有的依赖属性的基础使用。