WPF依赖项属性原理(原创)

WPF中提供了绑定、动画等让人激动的技术,而这些技术之所以可以实现,是因为WPF中强大的依赖项属性。而本篇文章的目的就是介绍依赖项属性的原理。依赖项属性有两个重要的特性:更改通知和属性值继承。

更改通知:当依赖项属性值被更改时,会得到通知,一般在绑定中使用。

属性值继承:某些依赖项属性可以从它的父元素中或元素树中的某个元素中得到。


在介绍依赖项属性前先看一下WPF中元素的继承关系,这是很有必要的。



                                       图1.1

在图1.1中可以看到WPF中元素的一部分继承关系,.net所有的类都继承于Object,由于WPF的STA(单线程亲和)特性,DispatcherObject类用于验证正在操作控件的线程是否是窗体线程。重点就在于DependencyObject类,它是依赖项属性的关键,下面会进行详细介绍,详见代码部分。

    /// <summary>
    /// 自定义类型
    /// </summary>
    public class CustomClass : FrameworkElement//继承于FrameworkElement
    {

        /// <summary>
        /// 私有成员
        /// </summary>
        private string name = string.Empty;

        /// <summary>
        /// .net属性
        /// </summary>
        public string Name
        {
            get//读访问器
            {
                return name;
            }
            set//写访问器
            {
                name = value;
            }
        }


        /// <summary>
        /// .net属性封装
        /// </summary>
        public int Age
        {
            get //读访问器
            { 
                return (int)GetValue(AgeProperty); 
            }
            set //写访问器
            { 
                SetValue(AgeProperty, value); 
            }
        }

        /// <summary>
        /// 声明并创建依赖项属性
        /// </summary>
        public static readonly DependencyProperty AgeProperty =
            DependencyProperty.Register("Age", typeof(int), typeof(CustomClass), new PropertyMetadata(18, CustomPropertyChangedCallback), CustomValidateValueCallback);

        /// <summary>
        /// 属性值更改回调方法
        /// </summary>
        /// <param name="d"></param>
        /// <param name="e"></param>
        private static void CustomPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {

        }

        /// <summary>
        /// 属性值验证回调方法
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        private static bool CustomValidateValueCallback(object value)
        {
            return true;
        }

    }
上面的代码中定义了CustomClass类,此类继承于FrameworkElement,这点非常重要,因为FrameworklElement继承于DependencyObject,所以才可以在自定义类中声明依赖项属性。

CustomClass类中声明了两个属性,一个是普通的.net属性,一个是依赖项属性。

.net属性:

普通.net属性很简单,它提供了面向对象的封装特性,代码如下。

        /// <summary>
        /// 私有成员
        /// </summary>
        private string name = string.Empty;

        /// <summary>
        /// .net属性
        /// </summary>
        public string Name
        {
            get//读访问器
            {
                return name;
            }
            set//写访问器
            {
                name = value;
            }
        }
.net属性很直观,首先有一个私有字段,然后是用属性来封装。属性中提供了读和写访问器,而且大家都应该知道的是,对此属性进行操作,实际上是在进行方法调用。读和写访问器在MSIL中变成了两个方法。



依赖项属性:

依赖项属性使用普通的.net属性封装,代码如下。

        /// <summary>
        /// .net属性封装
        /// </summary>
        public int Age
        {
            get //读访问器
            { 
                return (int)GetValue(AgeProperty); 
            }
            set //写访问器
            { 
                SetValue(AgeProperty, value); 
            }
        }

        /// <summary>
        /// 声明并创建依赖项属性
        /// </summary>
        public static readonly DependencyProperty AgeProperty =
            DependencyProperty.Register("Age", typeof(int), typeof(CustomClass), new PropertyMetadata(18, CustomPropertyChangedCallback), CustomValidateValueCallback);

        /// <summary>
        /// 属性值更改回调方法
        /// </summary>
        /// <param name="d"></param>
        /// <param name="e"></param>
        private static void CustomPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {

        }

        /// <summary>
        /// 属性值验证回调方法
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        private static bool CustomValidateValueCallback(object value)
        {
            return true;
        }

从上面的代码可以看到,首先使用.net的属性封装了新技术,从而使开发人员在开发过程中像使用普通的属性一样使用依赖项属性,代码如下

        /// <summary>
        /// .net属性封装
        /// </summary>
        public int Age
        {
            get //读访问器
            { 
                return (int)GetValue(AgeProperty); 
            }
            set //写访问器
            { 
                SetValue(AgeProperty, value); 
            }
        }

依赖项属性通过调用GetValue和SetValue方法实现读写操作,这两个方法是DependencyObject类中定义的,而且与本类有继承关系,所以可以直接调用这两个方法实现读取和设置依赖项属性,你也许会问,依赖项属性的值保存到哪了,而真实的情况是,属性值被保存到DependencyObject中,DependencyObject用于存储没有数量限制的依赖项属性的集合。依赖项属性的读写就是这么简单,而且GetValue和SetValue方法用也并不难理解。

下面是依赖项属性的声明部分。

        /// <summary>
        /// 声明并创建依赖项属性
        /// </summary>
        public static readonly DependencyProperty AgeProperty =
            DependencyProperty.Register("Age", typeof(int), typeof(CustomClass), new PropertyMetadata(18, CustomPropertyChangedCallback), CustomValidateValueCallback);

        /// <summary>
        /// 属性值更改回调方法
        /// </summary>
        /// <param name="d"></param>
        /// <param name="e"></param>
        private static void CustomPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {

        }

        /// <summary>
        /// 属性值验证回调方法
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        private static bool CustomValidateValueCallback(object value)
        {
            return true;
        }

上面代码依赖项属性前面的 static说明了此属性是类型的状态,AgeProperty是与类型有关系的,而readonly 表示此对象是只读的。代码中调用DependencyProperty类型的Register方法创建依赖项属性,此方法提供了多个参数的构造。

参数“Age”是属性名称。

参数typeof(int)是属性类型

参数typeof(CustomClass)是属性所属类型

参数new PropertyMetadata(18, CustomPropertyChangedCallback)是属性元数据,它用于定义依赖项属性中重要的信息,此对象构造方法的第一个参数18表示依赖项属性的默认值为18,第二个参数是一个委托对象,当属性值发生变化时CustomPropertyChangedCallback会被调用。

参数CustomValidateValueCallback可以验证依赖项属性设置是否合法,如果合法则返回true,如果不合法则返回false。

提示:

如果此时创建CustomClass对象,Name属性在创建对象后属性值就已经存在了,而Age依赖项属性实际上并没有为其分配属性值的空间,如果此时从Age中取值,则从属性元数据(new PropertyMetadata(18))中获取初始值。如果在代码中设置了Age属性,则属性值保存到了DependencyObject中,下一次取值时就会从DependencyObject中得到并不会从new PropertyMetadata(18)元数据中取默认值。


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
获取WPF自定义控件的依赖属性的数据流程如下: 1. 定义依赖属性:在自定义控件的代码中,定义一个依赖属性并注册该属性。例如: ``` public static readonly DependencyProperty MyPropertyProperty = DependencyProperty.Register( "MyProperty", typeof(string), typeof(MyControl), new PropertyMetadata("Default Value")); public string MyProperty { get { return (string)GetValue(MyPropertyProperty); } set { SetValue(MyPropertyProperty, value); } } ``` 2. 绑定依赖属性:在XAML中,将自定义控件的依赖属性绑定到其他控件或数据源。例如: ``` <local:MyControl MyProperty="{Binding MyData}" /> ``` 3. 获取依赖属性的值:当自定义控件被渲染时,WPF框架会自动调用依赖属性的get方法,从绑定的数据源中获取属性的值。如果没有绑定任何数据源,则使用属性的默认值。例如: ``` string myPropertyValue = myControlInstance.MyProperty; ``` 4. 监听依赖属性的变化:如果需要在属性值发生变化时执行一些自定义逻辑,可以在自定义控件中注册属性值变化的回调函数。例如: ``` public static readonly DependencyProperty MyPropertyProperty = DependencyProperty.Register( "MyProperty", typeof(string), typeof(MyControl), new PropertyMetadata("Default Value", OnMyPropertyChanged)); private static void OnMyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { // Execute custom logic when MyProperty value changes } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值