WPF中的属性- CLR属性和依赖属性

2017-01-13 19:11:13来源:CSDN作者:u014434080人点击

一、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属性的值发生变化时,与之绑定的对象仍然可以得到通知,依赖属性默认带有这样的功能。

文章转载自HymanLiuTS

最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台