WPF之依赖属性

简而言之,依赖属性就是一种可以自己没有值,并能通过使用Binding从数据源获得值(依赖在别人身上)的属性。而拥有依赖属性的对象被称为依赖对象

与传统的CLR属性和面向对象思想相比依赖属性有很多新颖之处:

  • 节省实例对内存的开销。因为属性值在其他对象那里,而不在使用依赖属性的对象这里,所以节省了内存开销。
  • 属性值可以通过Binding依赖在其他对象上。

依赖属性对内存的使用方式

传统的.NET开发中,一个对象所占用的内存控件在调用new操作符进行实例化的时候就已经决定了,而WPF允许对象在被创建的时候并不包含用于储存数据的控件,只保留在需要时候能够获得默认值,借用其他对象数据或者分配空间的能力,这种对象就称为依赖对象,而它这种实时获取数据的能力则依靠依赖属性来实现,注意依赖对象不是数据产生的对象,而是具备获取其他对象的数据的能力的对象。

需要注意的是ItemSource所绑定的属性,必须同时具备{get;set;},如果不允许用户修改,则{get;private set},但必须同时具备,否则绑定的UI元素不会显示名称.

在WPF中,依赖对象的概念被DependencyObject类所实现,依赖属性的概念被DependencyProperty类所实现。DependencyObject具有GetValue和SetValue两个方法,DependencyProperty必须以DependencyObject为宿主,以这两个方法来进行写入与读取。

public class DependencyOobject:DispatcherObject{
    public object GetValue(DependencyPropertyy dp)//从DependencyProperty对象获取数据
    {
        ...///
    }
    public void SetValue(DependencyProperty dp,object value)
    {
        ...///
    }
}

DependencyObject是WPF系统中相当底层的一个基类,所有UI控件都是依赖对象。

例子:

    <StackPanel Background="LightBlue">
        <TextBox x:Name="textBox1" BorderBrush="Black" Margin="5"/>
        <TextBox x:Name="textBox2" BorderBrush="Black" Margin="5"/>
        <Button x:Name="btn" Content="OK" Click="btn_Click"/>
    </StackPanel>
    public partial class MainWindow : Window
    {
        Student stu;
        public MainWindow()
        {
            InitializeComponent();
            stu = new Student();
            Binding binding = new Binding("Text") { Source = this.textBox1 };
            stu.SetBinding(Student.NameProperty, binding);
            textBox2.SetBinding(TextBox.TextProperty, new Binding("Name") { Source = stu });
        }

        private void btn_Click(object sender, RoutedEventArgs e)
        {
            MessageBox.Show(stu.Name);
        }
    }
    public class Student : DependencyObject
    {
        //注册依赖属性
        public static readonly DependencyProperty NameProperty =
            DependencyProperty.Register("Name", typeof(string), typeof(Student));
        //CLR包装属性
        public string Name
        {
            get { return (string)GetValue(NameProperty); }
            set { SetValue(NameProperty, value); }
        }
        //SetBinding包装
        public BindingExpressionBase SetBinding(DependencyProperty dp,BindingBase binding)
        {
            return BindingOperations.SetBinding(this, dp, binding);
        }

    }

image-20211114204437950

简单总结下创建依赖对象,使用依赖属性的三部曲:

  • 继承DependancyObject

  • 在依赖对象内用DependancyProperty.Register方法注册依赖属性

  • 用CLR属性进行包装,结合依赖对象的SetValueGetValue方法。

附加属性

附加属性将的是一个属性本来不属于某个对象,但由于某种需求而被后来附加上。也就是把对象放入一个特定的环境后哦,对象才具有的属性。

Demo:

    <StackPanel Background="LightBlue">

        <Button x:Name="btn" Content="OK" Click="btn_Click"/>
    </StackPanel>
namespace MessagePump
{

    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {

        public MainWindow()
        {
            InitializeComponent();

        }

        private void btn_Click(object sender, RoutedEventArgs e)
        {
            Human human = new Human();
            School.SetGrade(human, 6);
            int grade = School.GetGrade(human);
            MessageBox.Show(grade.ToString());
        }
    }
    public class School : DependencyObject
    {
        //通过GetGrade、SetGrade,调用Human的SetValue和GetValue方法,存储依赖变量的值。

        public static int GetGrade(DependencyObject obj)
        {
            return (int)obj.GetValue(GradeProperty);
        }

        public static void SetGrade(DependencyObject obj, int value)
        {
            obj.SetValue(GradeProperty, value);
        }

        // Using a DependencyProperty as the backing store for GradeProperty.  This enables animation, styling, binding, etc...(注册依赖变量)
        public static readonly DependencyProperty GradeProperty =
            DependencyProperty.RegisterAttached("Grade", typeof(int), typeof(School), new PropertyMetadata(0));
    }

    class Human : DependencyObject
    {

    }
}

image-20211114220702538

posted @ 2021-11-14 22:24  JohnYang819  阅读(165)  评论(2编辑  收藏  举报