WPF中的属性(一)- CLR属性和依赖属性

一、CLR属性
CLR(Common Language Running)属性,本质是将一个类中的字段进行封装,以达到控制字段获取以及赋值的目的。
如下的Student类,作为一个学生,年龄显然不能为负数如果想要对age这一字段进行限制,我们可以采用CLR属性进行如下改写,

public class Student
    {
        public int id;
        public string name;
        public int age;
    }

改写后:

public class Student
    {
        public int ID { get; set; }
        public string Name { get; set; }
        private int age;
        public int Age
        {
            get { return age; }
            set
            {
                if (value > 0)
                {
                    age = value;
                }
            }
        }
    }

采用CLR属性,可以很方便的控制某一字段的读和写,其本质其实就是类方法,类似于C++中封装的控制类对象成员获取和设置的方法。值得注意的是,WPF的Binding中Path的必须是CLR属性。
二、依赖属性(Dependency Property)
依赖属性的含义是自己没有值,能通过Binding从数据源获得值(依赖在别人身上)的属性,用于依赖属性的对象被称为依赖对象。
2.1 依赖属性减少了内存的开销。
在传统的.Net开发中,每一个类对象一旦被创建,它的所有字段也就被分配了存储空间,以TextBox为例,其包含了138个字段,一旦一个TextBox被创建,其138个字段也就被分配了内存空间,而我们常用的字段也就Text一个,这就造成了内存空间的浪费。依赖属性的出现,就是为了解决这一问题。WPF允许对象在创建时,不包含各个字段所占用的空间,而在使用这个字段时通过其他对象的数据或者实时分配空间,这种对象就是依赖对象,而它这种实时获取数据能力就是依靠依赖属性来实现。
WPF中支持依赖对象的类,需要继承自DependevcyObject,依赖属性的类需要继承自DependevcyProperty。DependevcyObject具有GetValue和SetValue两个方法,其都是以DependevcyProperty对象为参数,用于读取和存储依赖属性对象的值:

  public class Student:DependencyObject
{

    public object GetValue(DependencyProperty dp)
        {
            ...
        }

        public object SetValue(DependencyProperty dp,object value)
        {
            ...
        }

    }

DependevcyObject是WPF中很底层的一个基类,所有的UI控件都是依赖对象。
2.2 依赖属性的使用
下面我们自已定义一个支持创建依赖对象的类Student,并设置其依赖属性:

public class Student:DependencyObject
    {

        public static readonly DependencyProperty NameProperty =
            DependencyProperty.Register("Name", typeof(string), typeof(Student));

    }

从上面的类中我们应该注意到:
1、该类必须继承自DependencyObject。
2、NameProperty是依赖属性,Name是用于包装NameProperty这个依赖属性的包装器,依赖属性的命名规范是“包装器+Property”。
3、依赖属性前必须由 public static readonly DependencyProperty修饰,其生成时并非由New,而是用DependencyProperty.Register
4、DependencyProperty.Register的三个参数以此是用来存储依赖属性值的CLR属性、该CLR属性的类型、该DependencyObject对象的类型。
其实从上面的定义我们也可以看出,其实依赖属性的本质就是一个全局的静态的DependencyProperty对象,当我们在开发WPF程序时,系统会准备一个全局的Dictionnary存储了由和“Name”和“Student”类经过某算法生成的唯一键和DependencyProperty的对象组成键值对。而在DependencyObject基类中保存了一个可变的Dictionnary,保存所有和该DependencyObject相关依赖属性的键值以及该属性值,每个DependencyObject对象都有这样一个容器。当使用SetValue对依赖属性进行赋值时,需要先从自带的容器中找到该依赖属性键值,然后 对对应的属性值进行赋值,如果没有就增加一个键值对。当使用GetValue进行依赖属性值的获取时,DependencyObject对象会在其 Dictionnary中进行查找,找到该依赖属性的键值后,返回对应的值,若没找到,返回DependencyProperty对应的默认值(该值在DependencyProperty存储)。
另外,至此对于WPF的Bingding也应该具有了一个更深的认识,其需要绑定Target属性就是依赖属性,而这也是依赖属性最主要的使用方面。
对应的XMAL代码:

<Window x:Class="_7_7.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <TextBox Height="23" HorizontalAlignment="Left" Margin="184,72,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" />
        <TextBox Height="23" HorizontalAlignment="Left" Margin="184,133,0,0" Name="textBox2" VerticalAlignment="Top" Width="120" />
        <Button Content="设¦¨¨置?和¨ª获?取¨?依°¨¤赖¤¦Ì属º?性?" Height="23" HorizontalAlignment="Left" Margin="174,208,0,0" Name="button1" VerticalAlignment="Top" Width="162" Click="button1_Click" />
    </Grid>
</Window>

对应的按钮事件处理函数:

private void button1_Click(object sender, RoutedEventArgs e)
        {
            Student stu = new Student();
            stu.SetValue(Student.NameProperty, textBox1.Text);
            textBox2.Text=stu.GetValue(Student.NameProperty) as string;
        }

程序实现的效果就是在第一个编辑框输入某一个值时,会在第一个编辑框显示该值,而后台实现时先给Student对象的依赖属性NameProperty赋值,然后再读取。
这里写图片描述

而在通常情况下,我们在使用依赖属性时,都需要用CLR属性将其进行包装,这也是目前所有UI控件对依赖属性的处理方式:
public class Student:DependencyObject
    {
        public static readonly DependencyProperty NameProperty =
            DependencyProperty.Register("Name", typeof(string), typeof(Student));

        public string Name
        {
            get { return (string)GetValue(NameProperty); }
            set { SetValue(NameProperty, value); }
        }

}

而按钮的点击事件就可改成:

private void button1_Click(object sender, RoutedEventArgs e)
        {
            Student stu = new Student();
            stu.Name = textBox1.Text;
            textBox2.Text = stu.Name;
        }

这样我们就可以利用Student的CLR属性进行数据的绑定,作为Binding的path和目标,且虽然Student没有继承INotifyPropertyChanged接口,在CLR属性的值发生变化时,与之绑定的对象仍然可以得到通知,依赖属性默认带有这样的功能。

  • 5
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值