WPF 依赖属性和附加属性

embedded/2024/12/23 14:15:20/

除了普通的 CLR 属性, WPF 还有一套自己的属性系统。这个系统中的属性称为依赖属性

1. 依赖属性

为啥叫依赖属性?不叫阿猫阿狗属性?

通常我们定义一个普通 CLR 属性,其实就是获取和设置一个私有字段的值。假设声明了 100 个 CLR 属性,每个属性占用 8 个字节(byte)的私有字段。那么实例化 10000 个这个类,就至少消耗了 100 * 8 * 10000 = 7.63M 内存。实际上,并非用到所有的属性。这就造成了内存浪费。

如何解决这种属性资源浪费的问题?

现实中一个例子,假设出去旅游,不可能把所有的日常生活用品都带去,一般也就带上日常换洗衣物,像锅碗瓢盆、洗衣粉、厕纸、洗发水等都要带上,岂不乱成一锅。所以,有些东西可以在要用的时候再去获取。

这就是 WPF 依赖属性的理念, 依赖属性本身没有值, 它依赖绑定源来获取值

在 UserControl 中定义一个依赖属性,snippet 快捷方式(propdp),

public partial class DependencyPropertyDemo : UserControl
{/// <summary>/// 获取或设置MyProperty的值/// </summary>  public string MyProperty{get => (string)GetValue(MyPropertyProperty);set => SetValue(MyPropertyProperty, value);}/// <summary>/// 标识 MyProperty 依赖属性/// </summary>public static readonly DependencyProperty MyPropertyProperty =DependencyProperty.Register(nameof(MyProperty), typeof(string), typeof(DependencyPropertyDemo), new PropertyMetadata(default(string)));public DependencyPropertyDemo(){InitializeComponent();}
}

可以进方法 DependencyProperty.Register 查看,实质是调用内部 RegisterCommon 方法把属性注册到一个 Hashtable

private static Hashtable PropertyFromName = new Hashtable();private static DependencyProperty RegisterCommon(string name,Type propertyType,Type ownerType,PropertyMetadata defaultMetadata,ValidateValueCallback validateValueCallback){//...lock (DependencyProperty.Synchronized)DependencyProperty.PropertyFromName[(object) key] = (object) dependencyProperty;//...}

这有点类似设计模式中的 享元模式(Flyweight Pattern),使用哈希表存储已经创建的内存对象,来减少内存消耗。

通过 GetValue/SetValue方法, 可以获取/设置依赖属性(绑定数据源)的值。

疑问:我们没有在 DependencyPropertyDemo 类中定义 GetValue/SetValue 方法,为什么也能使用呢?
因为它们已在基类中定义好了。
在这里插入图片描述
实际上,任何继承于 DependencyObject 的类中都可以定义依赖属性。我们用到的可视化控件基本都是继承于 Viusal 的,自然可以声明依赖属性

2. 附加属性

附加属性,其实也是依赖属性

使用 sinppet (propa)快捷方式创建一个附加属性

public static readonly DependencyProperty MyAttachedProperty =DependencyProperty.RegisterAttached("MyAttached",typeof(string),typeof(MyAttachedHelper),new FrameworkPropertyMetadata(default(string),flags: FrameworkPropertyMetadataOptions.Inherits));public static string GetMyAttached(DependencyObject target)
{return (string)target.GetValue(MyAttachedProperty);
}public static void SetMyAttached(DependencyObject target, string value)
{target.SetValue(MyAttachedProperty, value);
}

可以看到,它最终也是调用 DependencyProperty.RegisterCommon 来注册属性,GetValue/SetValue 方法一样也是基类 DependencyObject 中的 GetValue/SetValue 方法。

只是附加属性的使用场景不太一样:

依赖属性: 当希望类中某个属性支持数据绑定时, 可以用依赖属性

附加属性: 当希望类可以绑定到某个数据源,但该类本身又没有这个依赖属性, 就可以借助其它类的依赖属性做绑定。这个过程即:类附加了其它类的一个依赖属性,简称附加属性

3. 完整示例

在自定义控件中声明一个依赖属性

public class MyControl : Control
{/// <summary>/// 获取或设置MyProperty的值/// </summary>  public string MyProperty{get => (string)GetValue(MyPropertyProperty);set => SetValue(MyPropertyProperty, value);}/// <summary>/// 标识 MyProperty 依赖属性/// </summary>public static readonly DependencyProperty MyPropertyProperty =DependencyProperty.Register(nameof(MyProperty), typeof(string), typeof(MyControl),new PropertyMetadata(default(string)));static MyControl(){DefaultStyleKeyProperty.OverrideMetadata(typeof(MyControl), new FrameworkPropertyMetadata(typeof(MyControl)));}
}

在另一个类中声明一个附加属性

public class MyAttachedHelper : DependencyObject
{public static readonly DependencyProperty MyAttachedProperty =DependencyProperty.RegisterAttached("MyAttached",typeof(string),typeof(MyAttachedHelper),new FrameworkPropertyMetadata(default(string),flags: FrameworkPropertyMetadataOptions.Inherits));public static string GetMyAttached(DependencyObject target){return (string)target.GetValue(MyAttachedProperty);}public static void SetMyAttached(DependencyObject target, string value){target.SetValue(MyAttachedProperty, value);}
}

为控件指定样式,

<Style TargetType="{x:Type controls:MyControl}"><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type controls:MyControl}"><Grid Background="DeepPink"><StackPanel Orientation="Horizontal"><TextBlockMargin="4"HorizontalAlignment="Center"VerticalAlignment="Center"Text="{TemplateBinding MyProperty}" /><TextBlockMargin="4"HorizontalAlignment="Center"VerticalAlignment="Center"Text="and" /><TextBlockMargin="4"HorizontalAlignment="Center"VerticalAlignment="Center"Text="{TemplateBinding viewModels:MyAttachedHelper.MyAttached}" /></StackPanel></Grid></ControlTemplate></Setter.Value></Setter>
</Style>

绑定数据源,

public class DpViewModel
{public string Name1 { get; set; }public string Name2  { get; set; }public DpViewModel(){Name1 = "Tom~";Name2 = "Jerry~";}
}

使用控件,

<Grid Width="200" Height="100"><controls:MyControl MyProperty="{Binding Name1}" viewModels:MyAttachedHelper.MyAttached="{Binding Name2}" />
</Grid>

显示结果,
在这里插入图片描述
均绑定成功。


http://www.ppmy.cn/embedded/148083.html

相关文章

xcode15 报错 does not contain ‘libarclite‘

新建pod私有库 在xcode15 无法运行 报错 SDK does not contain libarclite at the path /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/arc/libarclite_iphoneos.a; try increasing the minimum deployment target 下载 资源文件…

基于单片机的非接触式红外测温系统

功能介绍 采用51单片机作为主控系统&#xff1b; 通过MLX90614红外测温模块&#xff0c;精准测量温度&#xff1b; 通过红外传感器反应是否有人体靠近&#xff0c;靠近后开始测温&#xff1b; 通过TTS语音模块播报温度&#xff1b; 通过按键可以调节温度阀值通过LCD1602显示模块…

qqmusic for linux 启动闪退解决办法

出现问题&#xff1a;安装了双系统之后&#xff0c;想在linux物理机上安装qq音乐之后&#xff0c;但是启动发现闪退 我的系统是Zorin&#xff0c;基于Ubuntu的linux系统 解决办法是修改配置文件 文件位置&#xff1a;/usr/share/applications/qqmusic.desktop sudo vim /u…

新能源汽车充电需求攀升,智慧移动充电服务有哪些实际应用场景?

在新能源汽车行业迅猛发展的今天&#xff0c;智慧充电桩作为支持这一变革的关键基础设施&#xff0c;正在多个实际应用场景中发挥着重要作用。从公共停车场到高速公路服务区&#xff0c;从企业园区到住宅小区&#xff0c;智慧充电桩不仅提供了便捷的充电服务&#xff0c;还通过…

如何实现单例模式?

概念 单例模式&#xff08;Singleton Pattern&#xff09;是一种设计模式&#xff0c;确保一个类只有一个实例&#xff0c;并提供一个全局访问点。它常用于需要控制资源访问的场景&#xff0c;如数据库连接、日志记录或者配置管理等。 方式 懒汉式单例 懒汉式单例是在第一次…

工厂常用软件系统大全中英文全称对照表及功能介绍应用场景ERP MES WMS SCADA IOT SAP等软件系统介绍

1. ERP&#xff08;Enterprise Resource Planning&#xff09;企业资源计划&#xff1a; ○ 功能&#xff1a;整合企业的各项资源和业务流程&#xff0c;涵盖从采购、生产到销售的各个环节。包括财务管理、生产计划、采购管理、库存管理、销售管理、人力资源管理等。 ○ 应用场…

使用Laravel构建你的第一个Web应用

使用Laravel构建你的第一个Web应用 Laravel是一个现代化的PHP框架&#xff0c;以其优雅的语法和强大的功能而闻名。它提供了许多内置工具和功能&#xff0c;使得开发Web应用变得更加高效和便捷。本文将指导你如何使用Laravel构建你的第一个Web应用&#xff0c;涵盖环境设置、项…

2024年12月22日Github流行趋势

项目名称&#xff1a;donnemartin / system-design-primer 项目维护者&#xff1a;donnemartin, cclauss, satob, fluency03, linhe0x0 等项目介绍&#xff1a;学习如何设计大规模系统。为系统设计面试做准备。包括Anki闪卡。项目star数&#xff1a;280,653项目fork数&#xff…