WPF教程(一) 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;
    public string name;
    public int ID { get; set; }
    public string Name { get; set; }//CLR属性
    private int age;
    public int Age //CLR属性
    {
       get { return age; }
       set
         {
            if (value > 0)
            {
               age = value;
            }
         }
     }
 }

采用CLR属性,可以很方便的控制某一字段的读和写,其本质其实就是类方法,类似于C++中封装的控制类对象成员获取和设置的方法。值得注意的是,WPF的Binding中Path的必须是CLR属性。 

依赖属性(Dependency Property)的含义是自己没有值,能通过Binding从数据源获得值(依赖在别人身上)的属性,用于依赖属性的对象被称为依赖对象。 

在传统的.Net开发中,每一个类对象一旦被创建,它的所有字段会被分配了存储空间,以TextBox为例,其包含了138个字段,一旦一个TextBox被创建,其138个字段也就被分配了内存空间,而常用的字段也就Text一个,这就造成了内存空间的浪费。依赖属性的出现,就是为了解决这问题。WPF允许对象在创建时,不包含各个字段所占用的空间,而在使用这个字段时通过其他对象的数据或者实时分配空间,这种对象就是依赖对象,而它这种实时获取数据能力就是依靠依赖属性来实现。 

WPF中支持依赖对象的类,需要继承自DependevcyObject,依赖属性的类需要继承自DependevcyProperty。DependevcyObject具有GetValue和SetValue两个方法,其都是以DependevcyProperty对象为参数,用于读取和存储依赖属性对象的值。下面我们自已定义一个支持创建依赖对象的类Student,并设置其依赖属性:

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

}

NameProperty是依赖属性,Name是用于包装NameProperty这个依赖属性的包装器,依赖属性的命名规范是"包装器+Property"。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="DependencyAttribute.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;
   }

而在通常情况下,我们在使用依赖属性时,都需要用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属性的值发生变化时,与之绑定的对象仍然可以得到通知,依赖属性默认带有这样的功能。

猜你喜欢

转载自blog.csdn.net/yangwenxue1989/article/details/81366284