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

相关推荐
小杍随笔几秒前
【Rust 语言编程知识与应用:闭包详解】
开发语言·后端·rust
2301_764441336 分钟前
使用python构建的STAR实验ΛΛ̄自旋关联完整仿真
开发语言·python·算法
共享家95277 分钟前
Java入门( 异常 )
java·开发语言·php
御形封灵9 分钟前
基于canvas的路网编辑交互
开发语言·javascript·交互
xifangge202512 分钟前
Python 爬虫实战:爬取豆瓣电影 Top250 数据并进行可视化分析
开发语言·爬虫·python
SunnyDays101113 分钟前
C# 实战:快速查找并高亮 Word 文档中的文字(普通查找 + 正则表达式)
开发语言·c#
kaoshi100app16 分钟前
本周,河南二建报名公布!
开发语言·人工智能·职场和发展·学习方法
421!16 分钟前
ESP32学习笔记之GPIO
开发语言·笔记·单片机·嵌入式硬件·学习·算法·fpga开发
人工智能AI技术16 分钟前
Qwen3.5-Plus登顶|C#集成通义千问,高并发服务实战优化
人工智能·c#
problc27 分钟前
在 OpenClaw 里一句话记账:消费说出来,账单自动进乖猫记账 App
开发语言·python