CH04_依赖项属性

news2024/11/22 16:45:49

第4章:依赖项属性

本章目标

  • 理解依赖项属性
  • 理解属性验证

依赖项属性

​ 属性与事件是.NET抽象模型的核心部分。WPF使用了更高级的依赖项属性(Dependency Property)功能来替换原来.NET的属性,实现了更高效率的保存机制,还添加了附加功能,如属性变更通知以及强制回调、属性值继承(在逻辑树中向下传播默认属性值的能力)以及属性有效性验证等。同时,依赖项属性也是WPF许多重要功能的基础,包括动画、数据绑定以及样式。

​ 使用依赖项属性包括三个部分,定义依赖项属性;注册依赖项属性以及添加属性包装器。

定义依赖项属性

​ 定义依赖项属性,使用三个修饰词,public、static、readonly。数据类型为DependecyProperty,而每一个依赖项属性都会有一个去掉“Property”的CLR属性和他对应,而我们在xaml中访问的都是CLR属性。

​ 根据约定,定义依赖项属性的字段的名称是在普通属性的末尾处加上单词"Property"。根据这种命名方式,可以从实际属性的名称中区分出依赖项属性的定义。字段的定义使用了 readoly 关键字,这意味着只能在 FrameworkElement 类的静态构造函数中队旗进行设置。

​ 例如,FrameworkElement 类定义了 Margin 属性,在 FrameworkElement 类中需要使用类似下面的代码来定义Margin 属性:

在这里插入图片描述

注册依赖项属性

​ 定义 DependencyProperty对象只是第一步而已。为了使用依赖项属性,还需要使用 WPF注册创建的依赖项属性。这一步骤需要在任何使用属性的代码之前完成,因此必须在与其关联的类的静态构造函数中进行。

​ WPF 确保 DependencyProperty 对象不能被直接实例化,因为 DependencyProperty 类没有公有的构造函数。相反,只能使用静态的 DependencyProperty Register0方法创建 DependencyProperty实例。WPF 还确保在创建 DependencyProperty 对象后不能改变该对象,因为所有DependencyProperty 成员都是只读的。它们的值必须作为 Register0方法的参数来提供。
下面的代码显示了如何创建 DependencyProperty 对象。在此,FrameworkElement类使用静态构造函数来初始化 MarginProperty:

在这里插入图片描述

添加属性包装器

​ 创建依赖项属性的最后一个步骤是使用传统的.NET 属性封装WPF依赖项属性。但典型的过程是检索或设置某个私有字段的值,而WPF属性的属性过程是使用在 DependencyObject 基类中定义的 GetValue()和 SetValue()方法。

在这里插入图片描述

共享的依赖项属性

​ 尽管一些类具有不同的继承层次,但他们会共享同一依赖项属性。例如,TextBlock.FontFamily属性和 Control.FontFamily 属性指向同一个静态的依赖项属性,该属性实际上实在 TextElement 类中定义的 TextElement.FontFamilyProperty 依赖项属性。TextElement 类的静态构造函数注册该属性,而 TextBlock 类和Control 类的静态构造函数知识通过调用 DependencyProperty.AddOwner()方法重用该属性:

TextBlock类:

在这里插入图片描述

Control类:

在这里插入图片描述

附加的依赖项属性

​ 附加属性是一种依赖项属性,由WPF 属性系统管理。不同之处在于附加属性被应用到的类并非定义附加属性的那个类。例如,Grid 类定义了Row 和 Column 附加属性,这两个属性被用于设置Grid 面板包含的元素,以指明这些元素应被放到哪个单元格之中。类似的,DockPancel 类定义了 Dock 附加属性,而 Canvas 类定义了Left、Right、Top和Bottom 附加属性。

​ 为了定义附加属性,需要使用 RegisterAttached() 方法,而不是使用 Register() 方法.下面列举了一个注册Grid.Row 属性的例子:

在这里插入图片描述

​ 当创建附加属性时,不必定义.NET 属性封装器。这是因为附加属性可以被用于任何依赖对象。例如,Grid.Row 属性可能被用于 Grid 对象(如果在Grid 控件中嵌套了另一个Grid 控件),也可能被用于其他元素。实际上,Grid.Row 属性甚至可以被用于并不位于 Grid控件中的元素------- 甚至在元素树中根本就不存在 Grid 对象。

​ 不是使用 .NET 属性封装器,反而附加属性需要调佣两个静态方法来设置和获取属性值,这两个方法使用为人熟知的 SetValue() 和 GetValue() 方法(继承自 DependencyObject 类)。这两个静态方法应当命名为 SetPropertyName() 和 GetPropertyName().下面是实现 Grid.Row 附加属性的静态方法:

在这里插入图片描述

下面的示例使用代码将元素放到Grid 控件中第一行:

Grid.SetRow(txtElement,0)

也可直接调用 SetValue() 或 GetValue() 方法,从而绕过这两个静态方法:

txtElement.SetValue(Grid.RowProperty,0)

属性验证

​ 在定义任何类型的属性时,都需要面对错误设置属性的可能性。对于传统的.NET属性,可尝试在属性设置器中捕获这类问题。但对于依赖项属性而言,这种方法不合适,因为可能通过WPF 属性系统使用 SetValueO方法直接设置属性。

​ 作为代替,WPF 提供了两种方法来阻止非法值:

  • ValidateValueCallback:该回调函数可接受或拒绝新值。通常,该回调函数用于捕获违反属性约束的明显错误。可作为 DependencyProperty.Register()方法的一个参数提供该回调函数。
  • CoerceValueCallback:该回调函数可将新值修改为更能被接受的值。该回调函数通常用于处理为相同对象设置的依赖项属性值相互冲突的问题。这些值本身可能是合法的,但当同时应用时它们是不相容的。为了使用这个回调函数,当创建 Framework-PropertyMetadata 对象时(然后该对象将被传递到 DependencyProperty.Register()方法),作为构造函数的一个参数提供该回调函数。

下面是当应用程序试图设置依赖项属性时,所有这些内容的作用过程:

(1) 首先,CoerceValueCallback 方法有机会修改提供的值(通常,使提供的值和其他属性相容),或者返回 DependencyProperty.UnsetValue,这会完全拒绝修改。
(2) 接下来激活 Validate ValueCallback 方法。该方法返回 true 以接受一个值作为合法值,或者返回 false拒纯值。与 Coerce ValueCallback 方法不同,Validate ValueCallback 方法不能访问设置属性的实际对象,这意味着您不能检查其他属性值。
(3) 最后,如果前两个阶段都获得成功,就会触发 PropertyChangedCallback 方法。此时,如果希望为其他类提供通知,可以引发更改事件。

验证回调

​ DependencyProperty.Register() 方法接受可选的验证回调函数:

MarginProperty = DependencyProperty.Register(
"Margin", 
typeof(Thickness), 
_typeofThis, 
new FrameworkPropertyMetadata(default(Thickness),FrameworkPropertyMetadataOptions.AffectsMeasure), IsMarginValid);
private static bool IsMarginValid(object value)
{
    return ((Thickness)value).IsValid(allowNegative: true, allowNaN: false, allowPositiveInfinity: true, allowNegativeInfinity: false);
}

强制回调

​ 通过 FrameworkPropertyMetadata 对象使用 CoerceValueCallback 回调函数。

FrameworkPropertyMetadata metadata = new FrameworkPropertyMetadata();
metadata.CoerceValueCallback = new CoerceValueCallback(CoerceMaximum);

DependencyProperty.Register("Maximum",typeof(double),typeof(RangeBase),metadata);

​ 可以通过CoerceValueCallback 回调函数处理相互关联的属性。例如,ScrollBar 控件提供了 Maximum、Minimum 和 Value 属性,这些属性都继承自 RangeBase 类。保持对这些属性进行调整的一种方法是使用属性强制。例如,当设置Maximum 属性时,必须使用强制以确保不能小于 Minimum 属性的值:

在这里插入图片描述

​ 当设置 Value 属性时,会发送类似的强制过程。对 Value 属性进行强制,确保不会超出由 Minimum 和Maximum 属性定义的范围,使用下面的代码:

在这里插入图片描述

​ Minimum 属性根本不使用值强制。相反,一旦值发生变化,就触发PropertyChangedCallback,然后通过手动触发 Maximum 和 Value 属性的强制过程,使它们适应 Minimum 属性值的变化:

在这里插入图片描述

​ 类似的,一旦设置或强制 Maximum 属性的值,那么也会手动强制 Value 属性以适应 Maximum 属性值的变化:

在这里插入图片描述

​ 如果设置的值相互冲突,最终结果是 Minimum 属性具有优先权,其次是 Maximum 属性(并且可能会被 Minimum 属性强制),最后是 Value 属性(并且可能会被 Maximum 和 Minimum 属性强制)。

本章小结

​ 本章深入分析了 WPF 依赖项属性。首先介绍如何定义和注册依赖项属性,接下类介绍了如何将它们插入到其他 WPF 服务中,以及它们如何支持验证和强制。

课后作业

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1936279.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

卷积神经网络【CNN】--池化层的原理详细解读

池化层(Pooling Layer)是卷积神经网络(CNN)中的一个关键组件,主要用于减少特征图(feature maps)的维度,同时保留重要的特征信息。 一、池化层的含义 池化层在卷积神经网络中扮演着降…

python调用chrome浏览器自动化如何选择元素

功能描述:在对话框输入文字,并发送。 注意: # 定位到多行文本输入框并输入内容。在selenium 4版本中,元素定位需要填写父元素和子元素名。 textarea driver.find_element(By.CSS_SELECTOR,textarea.el-textarea__inner) from …

ACM中国图灵大会专题 | 图灵奖得主Manuel Blum教授与仓颉团队交流 | 华为论坛:面向全场景应用编程语言精彩回顾

ACM 中国图灵大会(ACM Turing Award Celebration Conference TURC 2024)于2024年7月5日至7日在长沙举行。本届大会由ACM主办,in cooperation with CCF,互联网之父Vinton Cerf、中国计算机学会前理事长梅宏院士和廖湘科院士担任学术…

linux进程——状态——linux与一般操作系统的状态

前言:博主在之前的文章已经讲解了PCB里面的pid——主要讲解了父子进程PID, 以及fork的相关内容。 本节进入PCB的下一个成员——状态, 状态是用来表示一个进程在内存中的状态的, 进程在内存中肯能处于各种状态, 比如运行…

十七、【机器学习】【非监督学习】- K-均值 (K-Means)

系列文章目录 第一章 【机器学习】初识机器学习 第二章 【机器学习】【监督学习】- 逻辑回归算法 (Logistic Regression) 第三章 【机器学习】【监督学习】- 支持向量机 (SVM) 第四章【机器学习】【监督学习】- K-近邻算法 (K-NN) 第五章【机器学习】【监督学习】- 决策树…

前端Vue组件化实践:自定义发送短信验证码弹框组件

在前端开发中,随着业务逻辑的日益复杂和交互需求的不断增长,传统的整体式开发方式逐渐暴露出效率低下、维护困难等问题。为了解决这些问题,组件化开发成为了一种流行的解决方案。通过组件化,我们可以将复杂的系统拆分成多个独立的…

使用 OpenCV 和 YOLO 模型进行实时目标检测并在视频流中显示检测结果

文章目录 Github官网简介视频帧推理视频设备ID安装依赖 检测示例分类示例姿势估计 Github https://github.com/ultralytics/ultralytics 官网 https://docs.ultralytics.com/zhhttps://docs.ultralytics.com/zh/quickstart/ 简介 Ultralytics 是一个软件公司,专…

深入浅出WebRTC—NACK

WebRTC 中的 NACK(Negative Acknowledgment)机制是实时通信中处理网络丢包的关键组件。网络丢包是常见的现象,尤其是在无线网络或不稳定连接中。NACK 机制旨在通过请求重传丢失的数据包来减少这种影响,从而保持通信的连续性和质量…

【VUE】v-if和v-for的优先级

v-if和v-for v-if 用来显示和隐藏元素 flag为true时&#xff0c;dom元素会被删除达到隐藏效果 <div class"boxIf" v-if"flag"></div>v-for用来进行遍历&#xff0c;可以遍历数字对象数组&#xff0c;会将整个元素遍历指定次数 <!-- 遍…

《数据结构:C语言实现双链表》

文章目录 一、链表的分类二、双向链表1、概念与结构 三、双向链表实现1、双向链表要实现的功能2、哨兵位初始化3、双链表头插数据4、判断链表是否为空5、打印链表数据6、尾插数据7、头删数据8、尾删数据9、寻找数据所在结点10、在任意结点之后插入数据11、删除任意结点12、销毁…

debian 更新源

前言 实现一键替换在线源 一键更新源 Debian 全球镜像站以下支持现有debian 11 12 echo "Delete the default source" rm -rf /etc/apt/sources.listecho "Build a new source" cat <<EOF>>/etc/apt/sources.list.d/debian.sources Types:…

Shell的正确使用

目录 shell 介绍 变量名的定义规则 变量名定义&#xff1a; 删除变量 特殊的变量名&#xff1a; 算术运算符 逻辑运算符&#xff1a; (1)整数之间比较 (2)按照文件权限进行判断 (3)按照文件类型判断 (4)多条件判断 常用的特殊字符&#xff1a; 条件选择、判断 if判…

PHP上门按摩专业版防东郊到家系统源码小程序

&#x1f486;‍♀️【尊享级体验】上门按摩专业版&#xff0c;告别东郊到家&#xff0c;解锁全新放松秘籍&#xff01;&#x1f3e0;✨ &#x1f525;【开篇安利&#xff0c;告别传统束缚】&#x1f525; 亲们&#xff0c;是不是厌倦了忙碌生活中的疲惫感&#xff1f;想要享…

NET 语言识别,语音控制操作、语音播报

System.Speech. 》》System.Speech.Synthesis; 语音播报 》》System.Speech.Recognition 语音识别 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Speech.Recog…

[Redis]典型应用——分布式锁

什么是分布式锁&#xff1f; 在一个分布式系统中&#xff0c;也会涉及到多个节点访问同一个公共资源的情况。此时就需要通过锁来做互斥控制&#xff0c;避免出现类似于"线程安全"的问题 举个例子&#xff0c;在平时抢票时&#xff0c;多个用户可能会同时买票&#…

Linux——多路复用之poll

目录 前言 一、poll的认识 二、poll的接口 三、poll的使用 前言 前面我们学习了多路复用的select&#xff0c;知道多路复用的原理与select的使用方法&#xff0c;但是select也有许多缺点&#xff0c;导致他的效率不算高。今天我们来学习poll的使用&#xff0c;看看poll较于…

利用AI与数据分析优化招聘决策

一、引言 在竞争激烈的职场环境中&#xff0c;招聘是组织获取人才、实现战略目标的关键环节。然而&#xff0c;传统的招聘方式往往依赖人力资源部门的主观经验和直觉&#xff0c;难以准确预测招聘效果&#xff0c;评估招聘渠道的效率。随着人工智能&#xff08;AI&#xff09;…

Windows右键新建Markdown文件类型配置 | Typora | VSCode

&#x1f64b;大家好&#xff01;我是毛毛张! &#x1f308;个人首页&#xff1a; 神马都会亿点点的毛毛张 今天毛毛张分享的是如何在右键的新建菜单中添加新建MarkdownFile文件&#xff0c;这是毛毛张分享的关于Typora软件的相关知识的第三期 文章目录 1.前言&#x1f3dd;…

Android车载MCU控制音量和ARM控制音量的区别和优缺点—TEF6686 FM/AM芯片

不要嫌前进的慢&#xff0c;只要一直在前进就好 文章目录 前言一、系统架构图1.MCU控制音量的架构图&#xff08;老方法&#xff09;2.ARM控制音量的架构图&#xff08;新方法&#xff09; 二、为啥控制音量不是用AudioManager而是执着去直接控制TDA7729&#xff1f;三、MCU控制…

[数据集][目标检测]婴儿车检测数据集VOC+YOLO格式1073张5类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;1073 标注数量(xml文件个数)&#xff1a;1073 标注数量(txt文件个数)&#xff1a;1073 标注…