博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
WPF 自定义依赖属性
阅读量:4324 次
发布时间:2019-06-06

本文共 4276 字,大约阅读时间需要 14 分钟。

 

DependencyObject和DependencyPorperty两个类是WPF属性系统的核心。

在WPF中,依赖对象的概念被DependencyObject类实现;依赖属性的概念则由DependencyPorperty类实现。

必须使用依赖对象作为依赖属性的宿主,二者结合起来,才能实现完整的Binding目标被数据所驱动。DependencyObject具有GetValue和SetValue两个方法,用来获取/设置依赖属性的值。

DependencyObject是WPF系统中相当底层的一个基类,如下:

从这颗继承树可以看出,WPF的所有UI控件都是依赖对象。WPF的类库在设计时充分利用了依赖属性的优势,UI空间的饿绝大多数属性都已经依赖化了。

下面用一个简单的实例来说明依赖属性的使用方法。先准备好一个界面,顺便复习下前面的Style和Template:

前面说过,DependencyProperty必须以DependencyObject为宿主、借助它的SetValue和GetValue方法进行写入和读取。因此,想用自定义的DependencyProperty,宿主一定是DependencyObject的派生类。

DependencyProperty实例的声明特点很明显:变量由public static readonly三个修饰符修饰,实例使用DependencyProperty.Register方法生成。而非new操作符得到。

代码如下:

using System.Windows;namespace DependencyObjectProperty{    class Student:DependencyObject    {        //定义依赖属性        public static readonly DependencyProperty NameProperty = DependencyProperty.Register("Name", typeof(string), typeof(Student));    }}

这是自定义DependencyProperty的最简单代码。

依赖属性也是属性,下面来使用它:

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

在textBox1中输入值,点下Button1后效果如下:

 

上面我们使用的依赖属性是靠GetValue和SetValue进行对外的暴露,而且在GetValue的时候需要进行类型的转换,因此,在大多数的情况下我们会为依赖属性添加一个CLR属性的外包装:

using System.Windows;namespace DependencyObjectProperty{    class Student:DependencyObject    {        //CLR属性进行封装        public string Name        {            get { return (string)GetValue(NameProperty); }            set { SetValue(NameProperty, value); }        }                //定义依赖属性        public static readonly DependencyProperty NameProperty = DependencyProperty.Register("Name", typeof(string), typeof(Student));    }}

有了这个CLR属性包装,我们就可以和CLR属性一样访问依赖属性了:

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

如果不关心底层的实现,下游的程序员在使用依赖属性时与使用单纯的CLR属性别无二致。

效果和上面相同:

 

 当然如果不用Binding,依赖属性的设计就没有意义,下面我们使用Binding把Student对象关联到textBox1上,再把textBox2关联到Student对象上。代码如下: 

private void button1_Click(object sender, RoutedEventArgs e){   Student stu = new Student();    Binding binding = new Binding("Text") { Source = textBox1 };   BindingOperations.SetBinding(stu, Student.NameProperty, binding);   Binding binding2 = new Binding("Name") { Source = stu };   BindingOperations.SetBinding(textBox2, TextBox.TextProperty, binding2);}

当然第二个Binding也可以这样写,下面两者等效:

Binding binding2 = new Binding("Name") { Source = stu };BindingOperations.SetBinding(textBox2, TextBox.TextProperty, binding2);
textBox2.SetBinding(TextBox.TextProperty, binding2);

也可以在Student类中封装FrameworkElement类的SetBinding方法,如下:

using System.Windows;using System.Windows.Data;namespace DependencyObjectProperty{    class Student:DependencyObject    {        //CLR属性进行封装        public string Name        {            get { return (string)GetValue(NameProperty); }            set { SetValue(NameProperty, value); }        }                //定义依赖属性        public static readonly DependencyProperty NameProperty = DependencyProperty.Register("Name", typeof(string), typeof(Student));        //SetBinding包装        public BindingExpressionBase SetBinding(DependencyProperty dp, BindingBase binding)        {            return BindingOperations.SetBinding(this, dp, binding);        }    }}

则Binding可进一步写成这样:

private void button1_Click(object sender, RoutedEventArgs e){   Student stu = new Student();   stu.SetBinding(Student.NameProperty, new Binding("Text") { Source=textBox1 });   textBox2.SetBinding(TextBox.TextProperty, new Binding("Name") { Source=stu});}

效果如下:

//---------------------------------------------------------

自定义依赖属性也可以不需要手动进行声明、注册并使用CLR属性进行封装,只需要输入propdp,同时连按两次Tab,一个标准的依赖属性(带CLR属性包装)就声明好了。

prop:CLR属性

propa:附加属性

propdp:依赖属性

附加属性也是一种特别的依赖属性,顾名思义,附加属性是说一个属性本来不属于某个对象,但是由于某种需求而被后来附加上。也就是把对象放入一个特定的环境后对象才具有的属性,比如Canvas.Left DockPanel.Dock Grid.Column等。

声明时一样用public static readonly三个关键词修饰。唯一不同就是注册附加属性使用的是名为RegisterAttached的方法,但参数与Register方法相同。附加属性的包装器也与依赖属性不同,依赖属性使用CLR属性对GetValue和SetValue两个方法进行包装,附加属性则使用两个方法分别进行包装。

其可由propa+tab+tab方便的生成。理解附加属性的意义及使用场合即可。

转载于:https://www.cnblogs.com/Jeely/p/11075837.html

你可能感兴趣的文章
阶段1 语言基础+高级_1-3-Java语言高级_08-JDK8新特性_第3节 两种获取Stream流的方式_9_Stream流中的常用方法_concat...
查看>>
阶段1 语言基础+高级_1-3-Java语言高级_08-JDK8新特性_第3节 两种获取Stream流的方式_11_练习:集合元素处理(Stream方式)...
查看>>
阶段1 语言基础+高级_1-3-Java语言高级_08-JDK8新特性_第4节 方法引用_1_方法引用基本介绍...
查看>>
阶段1 语言基础+高级_1-3-Java语言高级_08-JDK8新特性_第4节 方法引用_2_方法引用_通过对象名引用成员方法...
查看>>
阶段1 语言基础+高级_1-3-Java语言高级_08-JDK8新特性_第4节 方法引用_5_方法引用_通过this引用本类的成员...
查看>>
阶段1 语言基础+高级_1-3-Java语言高级_08-JDK8新特性_第4节 方法引用_7方法引用_数组的构造器引用...
查看>>
阶段1 语言基础+高级_1-3-Java语言高级_08-JDK8新特性_第4节 方法引用_3_方法引用_通过类名引用静态成员...
查看>>
阶段1 语言基础+高级_1-3-Java语言高级_09-基础加强_第1节 基础加强_3_Junit_使用步骤...
查看>>
阶段1 语言基础+高级_1-3-Java语言高级_08-JDK8新特性_第4节 方法引用_6_方法引用_类的构造器(构造方法)引用...
查看>>
阶段1 语言基础+高级_1-3-Java语言高级_09-基础加强_第2节 反射_5_反射_概述
查看>>
阶段1 语言基础+高级_1-3-Java语言高级_09-基础加强_第1节 基础加强_2_Junit_测试概述...
查看>>
阶段1 语言基础+高级_1-3-Java语言高级_09-基础加强_第2节 反射_7_反射_Class对象功能概述...
查看>>
阶段1 语言基础+高级_1-3-Java语言高级_09-基础加强_第1节 基础加强_4_Junit_@Before&@After...
查看>>
阶段1 语言基础+高级_1-3-Java语言高级_09-基础加强_第2节 反射_9_反射_Class对象功能_获取Constructor...
查看>>
阶段1 语言基础+高级_1-3-Java语言高级_09-基础加强_第2节 反射_6_反射_获取字节码Class对象的三种方式...
查看>>
阶段1 语言基础+高级_1-3-Java语言高级_09-基础加强_第2节 反射_11_反射_案例
查看>>
阶段1 语言基础+高级_1-3-Java语言高级_09-基础加强_第2节 反射_8_反射_Class对象功能_获取Field...
查看>>
阶段1 语言基础+高级_1-3-Java语言高级_09-基础加强_第2节 反射_10_反射_Class对象功能_获取Method成员方法...
查看>>
阶段1 语言基础+高级_1-3-Java语言高级_09-基础加强_第3节 注解_13_注解_JDK内置注解...
查看>>
阶段1 语言基础+高级_1-3-Java语言高级_09-基础加强_第3节 注解_12_注解_概念
查看>>