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

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

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

这里主要使用到 FrameworkPropertyMetadata 类型

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

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

AffectsArrange2

更改此依赖属性的值会触发布局组合的排列过程。

AffectsMeasure1

更改此依赖属性的值会触发布局组合的测量过程。

AffectsParentArrange8

更改此依赖属性的值会触发父元素上的排列过程。

AffectsParentMeasure4

更改此依赖属性的值会触发父元素上的测量过程。

AffectsRender16

更改此依赖属性的值会触发呈现或布局组合的某一方面(不是测量或排列过程)。

BindsTwoWayByDefault256

此依赖属性上的数据绑定的 BindingMode 默认为 TwoWay

Inherits32

此依赖属性的值将由子元素继承。容器控件嵌套

Journal1024

此依赖属性的值应由日记记录进程或在由统一资源标识符 (URI) 导航时进行保存或存储。

None0

未指定任何选项;依赖属性使用 WPF 属性系统的默认行为。

NotDataBindable128

不允许将数据绑定到此依赖属性。

OverridesInheritanceBehavior64

此依赖属性的值跨越分隔的树以实现属性值继承。

SubPropertiesDoNotAffectRender2048

此依赖属性值上的子属性不会影响呈现的任何方面。

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

<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控件模板,附加属性只提供值进行绑定。在左上角添加了一个小圆点。

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

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

<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>
  • 9
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

James.TCG

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值