DependencyObject类
之前说的DispatcherObject类 中dispatcher是调度员意思,因此那个类和调度有关。顾名思义,这个DependencyObject类是和依赖属性有关。
介绍依赖属性之前,先介绍两种驱动模式:
- 传统事件驱动模式 :
- 示例:在Winform中通过button1.Text = "确定"和button1.Text = "OK"分别修改按钮文本
- 特点: 需要主动修改控件属性值,业务逻辑复杂时需要编写大量赋值代码
- 数据驱动模式:
- 核心思想: 控件属性绑定变量,变量值变化时属性自动更新。类比说明: 类似数学函数"y=x ",y(控件属性)随x(绑定变量)变化而变化
- 优势: 减少手动赋值代码,实现数据与界面的自动同步
依赖属性 :DependencyProperty ,控件的属性不再被直接赋值,而是绑定了另一个"变量",当这个变量发生改变时,控件的属性也会跟着改变。
DependencyObject 类可以给控件提供这种数据驱动模式相关方式更新属性的值。其中最常用的方法就是GetValue()方法和SetValue()方法。
cs
public void SetValue(DependencyProperty dp, object value)
{
VerifyAccess();
PropertyMetadata metadata = SetupPropertyChange(dp);
SetValueCommon(dp, value, metadata, coerceWithDeferredReference: false, coerceWithCurrentValue: false, OperationType.Unknown, isInternal: false);
}
public object GetValue(DependencyProperty dp)
{
VerifyAccess();
if (dp == null)
{
throw new ArgumentNullException("dp");
}
return GetValueEntry(LookupEntry(dp.GlobalIndex), dp, null, RequestFlags.FullyResolved).Value;
}
SetValue方法用于设置依赖属性的值,参数为DependencyProperty对象和新值,新值为object类型。
GetValue方法用于获取某个依赖属性的值,参数为DependencyProperty对象,返回值为object类型。
不确定类型都定义为 object 类型。
Visual 类
Visual 类: WPF框架中第三个父类,提供呈现支持(命中测试、坐标转换、边界框计算)。
**作用:**控件显示的核心支持(位置、尺寸、颜色、转换、裁剪、边框计算)
注意与UIElement的区别(UIElement侧重交互,Visual侧重渲染)。
父类是 DependencyObject。
这个类目前主要知道作用即可。
UIElement类
UIElement类继承自Visual类,在WPF框架中属于第四个基类。
**作用:**将UI元素的通用属性和事件抽象集中,避免在具体控件中重复定义。
此类中包含了大量的路由事件定义和依赖属性定义,以及常用属性。
定义大量的依赖属性(以Property结尾,如VisibilityProperty):

定义了大量的路由事件( RoutedEvent)

什么是路由事件?
这个是官方文档介绍:

下面部分为老师ppt文档截取:
UIElement基类定义了大量的路由事件。什么是路由事件?路由事件和xaml的可视化树概念相关,控件的事件被触发后,会沿着这棵树广播,有两个方向,要么往树的根部广播,要么往树的枝叶广播,如果不广播就是直接事件。
所以,路由事件分为冒泡事件和隧道事件:冒泡,是从触发源为出发点,依次传递到父节点,直到最后的根节点;隧道事件是不管谁是触发源,都是从根节点触发,到子节点,直到触发节点。
从空间上来说,冒泡事件和隧道事件呈成对出现的 。从时间来说,都是先触发隧道事件,然后是冒泡事件。从命名来说,隧道事件都是以Preview开头的事件。
根据UIElement基类命名规则,我们可以大致猜测出一个结果,带Key的基本都是与键盘相关的事件(如按下键位、抬起键位),带Mouse的基本都是与鼠标相关的事件(如左键单击、双击),带Stylus的基本都是与触摸相关的事件,具体用到哪一类型的事件,请详细查阅一下相关说明文档即可。
重点:关于这些事件的回调函数,即以On开头的方法成员,都被声明成了protected virtual,意思是他们都可以被重载,这使得我们在开发业务时更加方便。
什么是回调函数?
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
下图是官方文档的介绍:

简单一点说就是,回调函数类似于房东,它有一个DLL函数(中介),如果要找回调函数(房东),需要把值给DLL函数(中介),由它来给回调函数(房东)。回调函数不能直接被调用。
一个中介可以对应很多的房东,可以带来很大便利。(优点)
**virtual:**声明虚方法,允许派生类重写。
**protected:**允许当前类和派生类读取和写入。
protected和virtual联合使用,配合注入容器,会给大型项目带来巨大便利的同时提高了可靠性。
目前还没写具体项目,对这点感触尚不深刻,先标记一下。这篇博客写了这个优势,以后常翻阅:
https://blog.csdn.net/qq_31116753/article/details/81203416
----------------------------------------2026/1/18--------------------------------------------------------