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

相关推荐
2501_93070778几秒前
使用 C# .NET 从 PowerPoint 演示文稿中提取背景图片
c#·powerpoint·.net
陳10304 分钟前
C++:红黑树
开发语言·c++
一切尽在,你来9 分钟前
C++ 零基础教程 - 第 6 讲 常用运算符教程
开发语言·c++
泉-java11 分钟前
第56条:为所有导出的API元素编写文档注释 《Effective Java》
java·开发语言
weixin_4997715530 分钟前
C++中的组合模式
开发语言·c++·算法
初级代码游戏31 分钟前
套路化编程 C# winform 自适应缩放布局
开发语言·c#·winform·自动布局·自动缩放
_waylau34 分钟前
鸿蒙架构师修炼之道-架构师的职责是什么?
开发语言·华为·harmonyos·鸿蒙
2的n次方_1 小时前
CANN Ascend C 编程语言深度解析:异构并行架构、显式存储层级与指令级精细化控制机制
c语言·开发语言·架构
java干货1 小时前
为什么 “File 10“ 排在 “File 2“ 前面?解决文件名排序的终极算法:自然排序
开发语言·python·算法
_F_y1 小时前
C语言重点知识总结(含KMP详细讲解)
c语言·开发语言