WPF核心学习——依赖属性

2019.07.24 流星飞宇

WPF中CLR 属性格式的属性比较常见,属性{get;set;},依赖属性是WPF一种特有的核心功能。MSDN原文中对依赖属性的设计思路的描述如下:
The purpose of dependency properties is to provide a way to compute the value of a property based on the value of other inputs. These other inputs might include system properties such as themes and user preference, just-in-time property determination mechanisms such as data binding and animations/storyboards, multiple-use templates such as resources and styles, or values known through parent-child relationships with other elements in the element tree.
依赖属性的的设计目的就是为了提供一种能够和其他诸如系统属性(主题和用户首选项)、实时属性确定机制(如数据绑定和动画/情节提要)、重用模板(如资源和样式或者通过与元素树中其他元素的父子关系来公开的值等等这些输入来交互的一种方式。
也就是说依赖属性就是用来在编程中与界面交互和控制的中间变量。WPF是一种数据驱动界面设计思想的语言框架,数据驱动界面,他们之间的中间媒介一定意义来说就是这个依赖属性,中间的交互方式就是数据绑定和事件体系,他们共同构成了WPF数据驱动界面这一构想的完成。
依赖属性换句话说就是自己没有值,通过使用binding从数据源获取到值(依赖在别人身上)的属性,通过依赖属性依赖的对象被称为“依赖对象”。举例来说,一个文本框的显示绑定到一个依赖对象身上,从此这个文本框的显示和这个依赖属性“同进同退”,对一个的赋值能够影响到另一个的值。这个思想可以有很多种用途,如测量仪器界面显示数值能够实时与当前测量的数值保持一致。
依赖对象是依赖属性的宿主。WPF中,每个控件动辄拥有上百个CLR属性,如果每个属性都有4字节,那么上百个属性将会占用4M以上的内存,而这只是一个控件,所以控件的属性实现方式都是依赖属性,因为依赖属性不会占用控件的内存。WPF的对象在被创建的时候并不包含存储数据的控件,只保留在需要用到数据时能够获得默认值、借用其他对象数据或者实时分配空间的能力。
依赖对象被DependencyObject实现,依赖属性是由DependencyProperty实现。
依赖属性的类继承关系
DependencyObject相当底层的一个类,所以WPF所有的UI控件都是依赖对象,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); }
        }
    }

(1)DependencyProperty存在于DependencyObject当中,所以Student继承DependencyObject类。
(2)DependencyProperty成员使用public static readonly修饰。
(3)依赖属性通过注册得到。第一个参数指明哪个CLR属性作为这个依赖属性的包装器。第二个参数指明依赖属性存储什么值。第三个参数指明宿主类型。
(3)同时通过CLR属性将依赖属性添加一个外包装。
此时假如创建一个对话框如下:

<Window x:Class="WpfApp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp1"
        mc:Ignorable="d"
        Title="MainWindow" Height="200" Width="300">
    <Grid>
        <StackPanel>
            <TextBox x:Name="textbox1" BorderBrush="Black" Margin="5"/>
            <TextBox x:Name="textbox2" BorderBrush="Black" Margin="5"/>
            <Button Content="OK" Margin="5" Click="Button_Click"/>
        </StackPanel>
    </Grid>
</Window>

在按钮的相应事件中添加:

private void Button_Click(object sender, RoutedEventArgs e)
        {
            stu = new Student();
            Binding binding = new Binding("Text") { Source = textbox1 };
            BindingOperations.SetBinding(stu, Student.nameProperty, binding);
            BindingOperations.SetBinding(textbox2, TextBox.TextProperty, new Binding("Name") { Source = stu });
        }

第一个绑定是将textbox1的内容绑定到stu的依赖属性上,第二个绑定是将textbox2的textproperty绑定到stu上。这样当点击按钮后就可以发现,textbox1输入什么,textbox2也会显示什么。
效果
DependencyProperty使用一个Hashtable注册依赖属性实例。注册依赖属性的时候,将使用第一个和第三个参数做异或求得哈希的key,然后存入到哈希表当中,当使用同一个名字和同一个宿主类型的时候注册会发生错误。WPF通过宿主类型和CLR属性名称就可以找到一个唯一的依赖属性实例。
实际工作中,依赖属性的值得来源比较多,可以来源于系统的存储,可能来自于元素的style,可能来自于继承,也可能来自于动画,依赖属性的值读取存在一个优先级顺序:
(1)WPF系统属性强制赋值。
(2)动画控制的值。
(3)本地变量值。
(4)上级元素的Template的值。
(5)隐式样式设置的值。
(6)样式之触发器的值。
(7)样式之设置器的值。
(8)默认样式的值。
(9)上级元素继承的值。
(10)默认值。
至此,依赖属性的学习就差不多了。依赖属性的设置实际上体现了WPF的一种设计思想,就是以public static类型的变量标记并以这个标记为索引进行对象的增删查改,这样的理念在之前的体系中不曾出现,这是WPF的创新,但是这也是WPF性能上不尽如人意的原因。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值