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

相关推荐
kkeeper~14 小时前
0基础C语言积跬步之深入理解指针(5下)
c语言·开发语言
一直不明飞行14 小时前
Java的equals(),hashCode()应该在什么时候重写
java·开发语言·jvm
盲敲代码的阿豪15 小时前
Python 入门基础教程(爬虫前置版)
开发语言·爬虫·python
曹牧15 小时前
C# WinForms应用程序中展示JSON内容
c#
basketball61615 小时前
C++ 构造函数完全指南:从入门到进阶
java·开发语言·c++
互联科技报15 小时前
2026超融合选型:Top5品牌与市场格局解读
开发语言·perl
weixin1997010801615 小时前
[特殊字符] 智能数据采集:数字化转型的“数据石油勘探队”(附Python实战源码)
开发语言·python
想唱rap16 小时前
IO多路转接之poll
服务器·开发语言·数据库·c++
@杰克成16 小时前
Java学习30
java·开发语言·学习
三品吉他手会点灯16 小时前
C语言学习笔记 - 40.数据类型 - scanf函数的编程规范与非法输入处理
c语言·开发语言·笔记·学习