WPF中依赖属性或附加属性的继承

引言

我们可以轻易的编写一个附加属性类,增加任意类型的附加属性并编写一定的逻辑来处理附加值的变化通知。假如控件是我们自定义的一个label、button 、textbox等,自定义控件当然是其他基础类型元素的组合,如shape、line、rectangle、geometry等对齐进行了装饰和功能增强,我们不希望重新编写或更改较多的窗体xaml代码,可以使用附加属性继承的方式,将附加属性传递到子元素,通过更改其控件模板实现极大程度上控件外观的重塑。

1、控件模板概述

WPF 中的许多控件使用 ControlTemplate 定义控件的结构和外观,因为它可以将控件的外观和功能区分开来。 重新定义 ControlTemplate 可以极大地更改控件的外观。 例如,假设需要在标签或左上角显示一个小圆点,以不同颜色表示状态。 由于 Label 使用控件模板定义外观,因此很容易重新定义 ControlTemplate 以符合该控件的要求,从而使用Label来制作交通信号灯。

尽管有些时候可以使用 DataTemplate,但在某些时候,光有 DataTemplate 还不够。 DataTemplate 定义控件内容的外观。 当外观要求与默认外观存在很大差异,有必要重新定义 ControlTemplate。 一般情况下,DataTemplate 用于定义控件的内容(或数据),ControlTemplate 用于定义控件的构成方式。

参阅:控件创作概述 - WPF .NET Framework | Microsoft Learn

|------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| UserControl | Xaml代码生成控件,无法使用 DataTemplate 或 ControlTemplate 来自定义其外观。 |
| Control | 能通过 ControlTemplate 进行自定义,支持不同主题 |
| FrameworkElement | 对控件的外观进行精确控制,而不仅仅是简单的元素组合提供的效果。可定义自己的呈现逻辑。重写 FrameworkElement 的 OnRender 方法,并提供显式定义组件视觉对象的 DrawingContext 操作。 |

2、可继承附加属性编写与使用

这里主要使用到 FrameworkPropertyMetadata 类型

官方注解此类派生自 PropertyMetadata () UIPropertyMetadata ,是专门为WPF 框架级应用程序开发目的准备的,此类是对基类PropertyMetadata的补充 ,包含指定或报告 WPF 框架级属性系统行为(如属性继承、数据绑定和布局)的各种布尔属性。

重点关注它的枚举参数类型FrameworkPropertyMetadataOptions

|--------------------------------|------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| AffectsArrange | 2 | 更改此依赖属性的值会触发布局组合的排列过程。 |
| AffectsMeasure | 1 | 更改此依赖属性的值会触发布局组合的测量过程。 |
| AffectsParentArrange | 8 | 更改此依赖属性的值会触发父元素上的排列过程。 |
| AffectsParentMeasure | 4 | 更改此依赖属性的值会触发父元素上的测量过程。 |
| AffectsRender | 16 | 更改此依赖属性的值会触发呈现或布局组合的某一方面(不是测量或排列过程)。 |
| BindsTwoWayByDefault | 256 | 此依赖属性上的数据绑定的 BindingMode 默认为 TwoWay。 |
| Inherits | 32 | 此依赖属性的值将由子元素继承。容器控件嵌套 |
| Journal | 1024 | 此依赖属性的值应由日记记录进程或在由统一资源标识符 (URI) 导航时进行保存或存储。 |
| None | 0 | 未指定任何选项;依赖属性使用 WPF 属性系统的默认行为。 |
| NotDataBindable | 128 | 不允许将数据绑定到此依赖属性。 |
| OverridesInheritanceBehavior | 64 | 此依赖属性的值跨越分隔的树以实现属性值继承。 |
| SubPropertiesDoNotAffectRender | 2048 | 此依赖属性值上的子属性不会影响呈现的任何方面。 |

如果不用继承,在更改了控件样式之后,我们通过附加属性更改其外观,则需要逐项去修改附加属性的值。如下:

cs 复制代码
<StackPanel wh:StatusDotElement.DotBrush="Red" wh:StatusDotElement.Radius="5">
    <Label Style="{DynamicResource StatusDotLabel}" Content="label1" wh:StatusDotElement.DotBrush="Red"/>
    <Label Style="{DynamicResource StatusDotLabel}" Content="label2" wh:StatusDotElement.DotBrush="Red"/>
    <Label Style="{DynamicResource StatusDotLabel}" Content="label3" wh:StatusDotElement.DotBrush="Red"/>
    <Label Style="{DynamicResource StatusDotLabel}" Content="label4" wh:StatusDotElement.DotBrush="Red"/>
</StackPanel>

这里重新定义了Label控件模板,附加属性只提供值进行绑定。在左上角添加了一个小圆点。

cs 复制代码
<ControlTemplate TargetType="Label">
    <hc:SimplePanel>
.....此处省略
        <Ellipse
            Margin="5"
            HorizontalAlignment="Left"
            VerticalAlignment="Top"
            Fill="{Binding Path=(attach:StatusDotElement.DotBrush), RelativeSource={RelativeSource TemplatedParent}}"
            Height="{Binding Path=(attach:StatusDotElement.Radius), RelativeSource={RelativeSource TemplatedParent}}"
            Width="{Binding Path=(attach:StatusDotElement.Radius), RelativeSource={RelativeSource TemplatedParent}}" />
    </hc:SimplePanel>

</ControlTemplate>

使用了继承之后只需设置一次:

cs 复制代码
<StackPanel wh:StatusDotElement.DotBrush="Red" wh:StatusDotElement.Radius="5">
    <Label Style="{DynamicResource StatusDotLabel}" Content="label1"/>
    <Label Style="{DynamicResource StatusDotLabel}" Content="label2"/>
    <Label Style="{DynamicResource StatusDotLabel}" Content="label3"/>
    <Label Style="{DynamicResource StatusDotLabel}" Content="label4"/>
</StackPanel>
相关推荐
蜗牛互联网11 小时前
OLMo-core 3的token gerrymandering提醒:MoE路由要按时间窗验收
java·人工智能·wpf
LateFrames15 小时前
WPF 升级选型:用 .NET 8 还是 .NET 10
.net·wpf·.net8·.net10
samble1 天前
从零搭建灌装监控系统(十):生产追溯,条码触发自动记录
c#·wpf·mvvm·modbus·工业控制
SamChan903 天前
PDF页面旋转与CropBox陷阱:译文回填位置总是错位的根因实测
python·ai·pdf·wpf
SamChan904 天前
PDF翻译时页眉页脚总在捣乱?跨页重复文本块的检测与过滤实测
人工智能·python·ai·pdf·wpf
samble11 天前
从零搭建灌装监控系统(四):深色主题与样式系统,ResourceDictionary 统一管理
c#·wpf·mvvm·样式·工业控制
_Jonas11 天前
.net framework开发环境正式环境配置文件的切换
.net·wpf
dalong1013 天前
WPF:Modbus 状态监控
wpf·modbus
He BianGu14 天前
【WPF-VisionMaster】机器视觉通用平台V5.0版本发行说明
opencv·c#·wpf·halcon·机器视觉·visionmaster
fogota17 天前
Emoji与Segoe MDL2 Assets的比较
c#·wpf