当前位置: 首页 > news >正文

WPF中依赖属性的底层和普通属性的底层有什么不一样

WPF中依赖属性的底层

在 WPF 中,依赖属性(Dependency Property)是 WPF 属性系统的核心,它支持功能强大的特性(如数据绑定、动画、样式等)。其底层实现是围绕 DependencyObject 类展开的。以下是 WPF 中依赖属性底层机制的关键点:

1. 依赖属性的注册与标识

注册过程

依赖属性是通过静态方法 DependencyProperty.Register 注册的。注册过程生成一个唯一的 DependencyProperty 标识符,用于标识该属性。

  • 注册时需要提供以下信息:

    1. 属性名(字符串形式)。
    2. 属性类型
    3. 所属类型(属性所属的类)。
    4. 元数据PropertyMetadata),可包含默认值、回调等信息。
  • 生成的 DependencyProperty 是一个静态字段,所有依赖属性的访问和操作都依赖它。

示例

public static readonly DependencyProperty MyProperty =DependencyProperty.Register("MyProperty",              // 属性名称typeof(int),               // 属性类型typeof(MyClass),           // 所属类new PropertyMetadata(0));  // 默认元数据

在底层,WPF 通过这个标识符将依赖属性映射到 DependencyObject 的属性存储系统中。

2. 依赖属性的存储系统

属性值存储

依赖属性值不直接存储在对象实例的字段中,而是存储在 DependencyObject 的全局属性存储系统中。

  • WPF 使用一个高效的内部数据结构(EffectiveValueEntry)来存储属性值。这种机制允许多个对象共享默认值,并在需要时动态计算和存储值。
  • 内存优化
    如果某个依赖属性使用的是默认值,那么属性存储系统中不会显式存储该值,而是通过查找元数据获取默认值。

3. 依赖属性的值计算

WPF 使用一个复杂的 优先级系统 来计算依赖属性的最终值。不同来源的值按照优先级规则合并。

值的来源与优先级

以下是依赖属性值的主要来源(按优先级从高到低):

  1. 本地值:通过 SetValue 显式设置的值。
  2. 动画:如果该属性正在动画化,动画值会覆盖本地值。
  3. 绑定:通过数据绑定设置的值。
  4. 样式和模板
    • 样式中的 Setter
    • 样式中的 Trigger
  5. 继承值:某些依赖属性可以从逻辑树中的父元素继承。
  6. 默认值:通过元数据指定的默认值。

示例

当获取依赖属性值时,WPF 会按优先级从高到低依次检查这些来源,找到最高优先级的值作为最终值。

4. 依赖属性的回调机制

依赖属性支持两种回调:

  1. PropertyChangedCallback:当属性值发生变化时触发。
  2. CoerceValueCallback:允许动态调整属性值。

示例

public static readonly DependencyProperty MyProperty =DependencyProperty.Register("MyProperty",typeof(int),typeof(MyClass),new PropertyMetadata(0, OnMyPropertyChanged));private static void OnMyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{// 属性值变化时的逻辑
}

回调机制是 WPF 属性系统的核心特性,允许开发者在属性值变化时执行自定义逻辑。

5. 依赖属性的性能优化

惰性加载(Lazy Loading)

WPF 的依赖属性系统对属性存储进行了优化:

  • 如果属性值未显式设置,则不会占用额外的存储空间。
  • 属性值使用时才动态计算。

批量更新

为了提高性能,WPF 使用了一个批处理机制(DependencyObject 的内部变更通知队列),避免频繁触发 UI 更新。

6. 依赖属性的继承

某些依赖属性(如 DataContext)支持从逻辑树中父元素自动继承值。这是通过 FrameworkPropertyMetadataInherits 标志实现的。

示例

FrameworkPropertyMetadata metadata = new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits);
DependencyProperty.Register("MyInheritedProperty", typeof(string), typeof(MyClass), metadata);

继承机制的底层依赖于 WPF 的逻辑树结构,值会从父元素传播到子元素。

7. 依赖属性与 CLR 属性的关系

依赖属性通常会通过包装 CLR 属性进行访问。CLR 属性的 gettersetter 调用 GetValueSetValue 方法。

示例

public int MyProperty
{get { return (int)GetValue(MyPropertyProperty); }set { SetValue(MyPropertyProperty, value); }
}

8. 依赖属性与附加属性

附加属性(Attached Property)是依赖属性的一种特殊形式,允许将属性附加到其他类的实例上。其底层仍使用 DependencyProperty 系统,但通过静态方法访问。

示例

public static readonly DependencyProperty MyAttachedProperty =DependencyProperty.RegisterAttached("MyAttached",typeof(int),typeof(MyClass),new PropertyMetadata(0));public static int GetMyAttached(DependencyObject obj)
{return (int)obj.GetValue(MyAttachedProperty);
}public static void SetMyAttached(DependencyObject obj, int value)
{obj.SetValue(MyAttachedProperty, value);
}

9. 底层类的作用

  • DependencyObject
    所有支持依赖属性的类的基类,提供 GetValueSetValue 方法,以及属性存储和变更通知机制。

  • DependencyProperty
    静态标识符类,用于标识依赖属性。

  • PropertyMetadata
    定义依赖属性的元数据,包括默认值和回调方法。

  • FrameworkPropertyMetadata
    PropertyMetadata 的扩展,支持 WPF 框架特性(如继承、AffectsRender 等)。

总结

依赖属性是 WPF 属性系统的核心,其底层机制基于 DependencyObject 的高效存储和动态值计算能力。通过统一的存储系统、优先级规则和回调机制,依赖属性为 WPF 提供了数据绑定、样式、动画等高级功能,同时在性能和灵活性之间达成了平衡。

http://www.lryc.cn/news/505595.html

相关文章:

  • 【Qt】drawText字体大小问题探究
  • Mapbox-GL 的源码解读的一般步骤
  • 【C++】高级分析 switch 语句的应用
  • 活动预告 | Surface 来了#11:Windows 11 AI+ PC,释放 AI 办公设备的无限潜能
  • php基础:正则表达式
  • go语言压缩[]byte数据为zlib格式的时候,耗时较多,应该怎么修改?
  • [机器学习]AdaBoost(数学原理 + 例子解释 + 代码实战)
  • 深入了解Spring
  • jar 包如何下载
  • ESlint代码规范,手动与自动修复
  • 利用编程获得money?
  • 设计规规范:【App 配色】
  • react 使用 PersistGate 白屏解决方案
  • F5中获取客户端ip地址(client ip)
  • Maven(生命周期、POM、模块化、聚合、依赖管理)详解
  • 电力场景绝缘子缺陷识别分割数据集labelme格式1099张3类别
  • 【k8s集群应用】Kubernetes 容器编排系统
  • Unity3D仿星露谷物语开发2之工程初始化
  • Kafka篇之参数优化进而提高kafka集群性能
  • 关于SAP Router连接不稳定的改良
  • 使用pygame做游戏(2):2048游戏的进一步改造,以失败告终
  • 【CSS in Depth 2 精译_078】12.6 调整字间距,提升可读性 + 12.7 本章小结
  • 泷羽sec学习打卡-brupsuite7搭建IP炮台
  • 使用Svelte构建轻量级应用详解
  • Qt设置部件的阴影效果
  • Python 助力 DBA:高效批量管理数据库服务器的多线程解决方案-多库查询汇总工具实现
  • vue响应式数据-修改对象的属性值,视图不更新
  • 【OpenCV计算机视觉】图像处理——平滑
  • C#编程报错- “ComboBox”是“...ComboBox”和“...ComboBox”之间的不明确的引用
  • JAVA:访问者模式(Visitor Pattern)的技术指南