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. myeclipse10.7导出war包时出错解决办法

    myeclipse10.7的版本破解后,导出war包时报“SECURITY ALERT: INTEGERITY CHECK ERROR”的错误. 选中项目->export->java ee ...

  2. winrar命令行参数说明

    用法:     rar <命令> -<开关 1> -<开关 N> <压缩文件> <文件...> <@列表文件...> <解 ...

  3. python多线程的适用场景

    1.多线程对于计算密集型无用 需求:列表li1每个元素加1,列表li2每个元素加100 # 导入模块 import threading li1 = [11, 22, 33] # +1 li2 = [4 ...

  4. oracle Dba之路

    如何快速的成为一个合格的 DBA? 2010年11月03日 11:25:00 阅读数:584 原文来自:http://topic.csdn.net/u/20101031/21/A78B2EA1-6F2 ...

  5. Q35+uefi or bios+legacy // PCI | PCIE

    1:首先统一可扩展固件接口(UEFI)是一种规范定义操作系统和平台固件之间的软件接口. UEFI旨在替代基本输入/输出系统(BIOS)固件接口.(legacy) 硬件平台厂商越来越多地采用UEFI管理 ...

  6. 转:用unix socket加速php-fpm、mysql、redis的连接

    图虫的服务器长期是单机运行.估计除了mysql之外,php-fpm和redis还可以在单机上共存很长时间.(多说服务器早就达成了单机每日2000万+动态请求,所以我对单机搞定图虫的大流量非常乐观) 如 ...

  7. mysql第三天作业

    1.将所有的课程的名称以及对应的任课老师姓名打印出来,如下:SELECT cname,tname FROM course LEFT JOIN teacher ON teacher.tid=course ...

  8. 2016年国内开源maven镜像站点汇总

    本文系转载,原文链接:https://www.cnblogs.com/xunianchong/p/5684042.html 一.站点版 (一).企业站 1.网易:http://mirrors.163. ...

  9. 从零到一创建ionic移动app:应用anjularjs编写ionic项目

    推荐两篇文章,带你入门 ionic中文项目(作为了解ionic基础结构用):http://blog.csdn.net/i348018533/article/details/47258449/ ioni ...

  10. 杭电1022Train Problem I

    地址:http://acm.hdu.edu.cn/showproblem.php?pid=1022 题目: Problem Description As the new term comes, the ...