C# DependencyObject类、Visual类、UIElement类

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--------------------------------------------------------

相关推荐
仟濹3 小时前
【Java基础】多态 | 打卡day2
java·开发语言
孞㐑¥3 小时前
算法——BFS
开发语言·c++·经验分享·笔记·算法
Re.不晚3 小时前
JAVA进阶之路——无奖问答挑战2
java·开发语言
bugcome_com3 小时前
深入了解 C# 编程环境及其开发工具
c#
八零后琐话3 小时前
干货:程序员必备性能分析工具——Arthas火焰图
开发语言·python
3GPP仿真实验室3 小时前
【MATLAB源码】CORDIC-QR :基于Cordic硬件级矩阵QR分解
开发语言·matlab·矩阵
知南x3 小时前
【Ascend C系列课程(高级)】(1) 算子调试+调优
c语言·开发语言
忆~遂愿3 小时前
GE 引擎与算子版本控制:确保前向兼容性与图重写策略的稳定性
大数据·开发语言·docker
Ro Jace4 小时前
计算机专业基础教材
java·开发语言
代码游侠4 小时前
学习笔记——设备树基础
linux·运维·开发语言·单片机·算法