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

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

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

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

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

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

<Window x:Class="DependencyObjectProperty.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="" Width="">
<Window.Resources>
<Style x:Key="textStyle" TargetType="{x:Type TextBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<TextBlock Background="CadetBlue" Foreground="HotPink" Text="{TemplateBinding Property=Text}"/>
</ControlTemplate>
</Setter.Value>
</Setter> <Style.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Border SnapsToDevicePixels="true" x:Name="Bd" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
<ScrollViewer SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" x:Name="PART_ContentHost" Background="AliceBlue"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<StackPanel>
<TextBox Style="{StaticResource textStyle}" Height="" Name="textBox1" FontSize="" Margin="" Width="" />
<TextBox Style="{StaticResource textStyle}" Height="" Name="textBox2" FontSize="" Margin="" Width="" />
<Button Content="Button" Height="" Name="button1" Width="" Click="button1_Click" />
</StackPanel>
</Window>

前面说过,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方便的生成。理解附加属性的意义及使用场合即可。

WPF 自定义依赖属性的更多相关文章

  1. WPF自定义依赖集合属性无法触发更新的问题

    通常WPF中通过继承UserControl的来快速创建自定义控件,最近项目上需要设计一个卫星星图显示控件,最终效果如下图所示.完成过程中遇到了自定义集合依赖属性无法触发更新通知的问题,在此记录一下,方 ...

  2. WPF 中依赖属性的继承(Inherits)

    WPF中依赖属性的值是是可以设置为可继承(Inherits)的,这种模式下,父节点的依赖属性会将其值传递给子节点.例如,数据绑定中经常使用的DataContextProperty: var host ...

  3. WPF 使用依赖属性(DependencyProperty) 定义用户控件中的Image Source属性

    原文:WPF 使用依赖属性(DependencyProperty) 定义用户控件中的Image Source属性 如果你要自定义一个图片按钮控件,那么如何在主窗体绑定这个控件上图片的Source呢? ...

  4. WPF的依赖属性和附加属性(用法解释较全)

    转:https://www.cnblogs.com/zhili/p/WPFDependencyProperty.html 一.引言 感觉最近都颓废了,好久没有学习写博文了,出于负罪感,今天强烈逼迫自己 ...

  5. WPF 之 依赖属性与附加属性(五)

    一.CLR 属性 ​ 程序的本质是"数据+算法",或者说用算法来处理数据以期得到输出结果.在程序中,数据表现为各种各样的变量,算法则表现为各种各样的函数(操作符是函数的简记法). ...

  6. WPF的依赖属性

    Windows Presentation Foundation (WPF) 提供了一组服务,这些服务可用于扩展公共语言运行时 (CLR)属性的功能,这些服务通常统称为 WPF 属性系统.由 WPF 属 ...

  7. wpf 的依赖属性只能在loaded 事件之后才能取到

    wpf 的依赖属性只能在loaded 事件之后才能取到,在构造函数的  InitializeComponent(); 之后取不到 wpf 的依赖属性只能在loaded 事件之后才能取到,在构造函数的  ...

  8. WPF 用户控件的自定义依赖属性在 MVVM 模式下的使用备忘

    依赖属性相当于扩充了 WPF 标签的原有属性列表,并可以使用 WPF 的绑定功能,可谓是十分方便的:用户控件则相当于代码重用的一种方式:以上几点分开来还是比较好理解的,不过要用到MVVM 模式中,还是 ...

  9. WPF usercontrol 自定义依赖属性

    1.依赖属性不同意一般属性,一般属性主要定义在对象中,而依赖属性是存在一个特殊的依赖属性表中.2.当我们触发改变值时,需要通过SetValue这种方式进行触发. UserControl1.xaml: ...

随机推荐

  1. pre 布局

    w

  2. 面试题15:链表中倒数第K个结点

    输入一个链表,输出该链表中倒数第k个结点. 方法1: 这个解法要循环两次链表 /* public class ListNode { int val; ListNode next = null; Lis ...

  3. Redis2.8配置文件详解(转)

    add by zhj : 没找到本文的原文.另外,redis配置文件中文翻译 也翻译的不错,可以与本文对照看.两篇文章都是以Redis2.8来介绍的 在Redis中直接启动redis-server服务 ...

  4. Linux bridge 资料链接

    1.Performance Evalution of Linux Bridge https://tnt.aufbix.org/_media/linux/yu-linux-tsm2004.pdf 2.L ...

  5. 《深入理解Linux网络技术内幕》阅读笔记 --- 邻居子系统

    1.封包从L3至L2的传送过程如下所示: 本地主机的路由子系统选择L3目的地址(下一个跃点). 根据路由表,如果下一个跃点在同一个网络中,邻居层就把目的L3地址解析为跃点的L2地址.这个关联会被放入缓 ...

  6. Linux(3)- 用户管理、文件与目录权限、常用命令、Linux软件包管理

    一.用户管理 现代操作系统一般属于多用户的操作系统,也就是说,同一台机器可以为多个用户建立账户,一般这些用户都是为普通用户,这些普通用户能同时登录这台计算机,计算机对这些用户分配一定的资源. 普通用户 ...

  7. Keras网络层之常用层Core

    常用层 常用层对应于core模块,core内部定义了一系列常用的网络层,包括全连接.激活层等 Dense层 keras.layers.core.Dense(units, activation=None ...

  8. boost atomic

    文档: http://www.boost.org/doc/libs/1_53_0/doc/html/atomic.html Presenting Boost.Atomic Boost.Atomic i ...

  9. mysql如果主库宕机,如何解决?

    两种情况服务器down机,数据库down机 如果此时需要切从库 1.先show processlist\G,查看状态 如果看到两个状态,说明此时的从库和主库是同步的 state: waiting fo ...

  10. Visual Studio 2012的Windows Service服务安装方式

    windows服务应用程序是一种长期运行在操作系统后台的程序,它对于服务器环境特别适合,它没有用户界面,不会产生任何可视输出,任何用户输出都回被写进windows事件日志.计算机启动时,服务会自动开始 ...