WPF 从 用户控件 到 自定义控件

WPF 从 用户控件 到 自定义控件

独立观察员 2024 年 4 月 29 日

98bf2f609af77ee6f7b782f4d18dd244.jpeg

一、用户控件示例:能够朝向上下左右四种方向

在 WPF 中,如果想要复用 Xaml 代码,最先想到的肯定是用户控件(UserControl),比如下面这个示例。

定义依赖属性 Direction(默认朝右):

1d57f6b28433f25d3aae764f6bba9451.png

类型为 DockPanel 的 Dock 枚举类型:

934b5e864771883f81b40ff7e773fd77.png

前台使用触发器来旋转相应的角度:

b1a528941d940a0693f72e9c13995e1e.png

二、让用户控件能够被设置全局样式

用户控件做好之后,在使用时,如果直接在它身上设置各个属性,一般都没什么问题。但是,由于这些属性一般具有重复性,所以和其它控件元素使用时一样,也就是如果在某个容器内有一系列相同元素,而且它们的很多属性也是会被设置为相同的,那么这时一般会在该容器的资源中添加一个针对该元素的样式,而且一般不设置 Key,也就是所谓的全局样式。下面描述一种给用户控件设置全局样式时不生效的情况及初步解决方法。

由于需要使用 DataTrigger,而且需要设置内部元素的属性,所以触发器需要和内容放在一起,这样就形成了【用户控件中只有一个针对自身的样式,且主要是用来设置控件模板】的局面:

a5cd8929f4650abf423ff46b93e1ed63.png

【修正 1】上图中将触发器放在 UserControl 的 Style 里,会导致外面使用时,给 UserControl 设置全局样式时不生效(尤其是对于依赖属性),可按照如下结构改造:

不过这又导致在 UserControl 上设置了默认值的属性,在外面全局样式设置时不能生效。

83956b7e9bfda422c6782f21025af239.png

【尝试】在用户控件资源中添加目标类型为自己的样式,在其中设置需要设置的默认值:

a94a04b6f72005577c994a6497fffacf.png

在使用时会提示未找到相关资源:

2950bb0ba7bd6ae6e74f5d713555eed3.png

这个想想也正常,相关样式资源是定义在用户控件内部的,在外面自然是访问不到的。

【修正 2】那么自然而然地就会想着把这个样式资源定义到全局可访问的地方去(比如 App.xaml),或者使用者会引用的资源字典中:

30b66d38c587ef4a6060007cfdd45832.png

然后再来使用的地方看看,BaseOn 不报错了,全局样式设置时,除了 Padding 因为直接在用户控件上设置了默认值导致未生效之外,其余都生效了:

f13fd9fd05689f49470e392aeca025ac.png

不过这么一折腾,最后发现,这不就是殊途同归到了 “自定义控件(CustomControl)” 上去了嘛?

得,还是改为自定义控件吧。这用户控件,真是从 质疑自定义控件,到 理解自定义控件,再到 成为自定义控件 啊。

三、迁移为自定义控件

新建自定义控件:

c0eb2cecaee4760a02b9206d4e42f6b8.png

修改名称后会生成一个继承自 Control(也可以自己手动改为 ContentControl 或其它类型) 的类,还会在 Themes/Generic.xaml 文件(这个文件中的资源会被自动加载)中添加默认的样式:

befe80465fedaa1494d9dafd6bf7589f.png

自定义控件类的构造函数中就是指定了这个样式,来看看这个指定的语句:

d252d2cbc4854dbd66b6918f9684d696.png

也就是指定了 DefaultStyleKey 这个依赖属性的默认值:

505c964ca59d00940ecc848ef7c77c57.png

然后就可以将之前的控件模板包括触发器拷贝过来了,自带属性改为使用 TemplateBinding 进行绑定,依赖属性使用 Binding 进行绑定,可以使用 Setter 设置默认值:

(有个缺点:绑定的依赖属性在 Xaml 中无法定位过去,这可能是 DataContext 方面的原因)

5f3c16eea30c72953f12cf7c6190683b.png

将之前的依赖属性拷贝到自定义控件类中:

207fbf3ae885889085a0f66df9b1ba1e.png

然后使用时即可随意设置属性了,也支持全局样式设置,而且不需要 BaseOn:

bf73faa693e9b56a4b449e2f0a928449.png

看来还是自定义控件强大啊,就是这个样式与类分离开来(不像用户控件一样在一个前后台)的组织形式有点不舒服,希望微软改进。

四、相关资源

自定义控件 CircleWithTextBlock 现已加入 NuGet 包 WPFTemplateLib 套餐:

6d1af054a9ec6ee644de5f6b3fe6b25d.png

示例代码:https://gitee.com/dlgcy/DLGCY_WPFPractice/tree/Blog20240429

2dfd29cdbf6666036b23b464a8a60aae.png

原创文章,转载请注明: 转载自 独立观察员 (dlgcy.com)

本文链接地址: [WPF 从 用户控件 到 自定义控件](https://dlgcy.com/wpf-from-usercontrol-to-customcontrol/)

关注微信公众号 独立观察员博客(DLGCY_BLOG) 第一时间获取最新文章

5ca7e50ba013ac0256758b2044bb363a.png

WPF

WPF 中的圆形不够圆?

WPF 多个 ScrollViewer 滚动同步

C# 或 WPF 中如何判断两个颜色是否近似

WPF 路由事件和附加事件简明教程

WPF 消息传递简明教程

WPF 属性变动后的业务处理及恢复原始值的方法

我向 ChatGPT 讨教了一下 WPF 中的行为 Behavior

使用通用附加属性来减少 WPF 元素自定义样式的多余代码

几十款 WPF 控件 - UI 库,总有一款适合你

WPF 用户控件分享之边上带输入框的圆圈

分享一个 WPF 气泡弹框

WPF 表单验证之 INotifyDataErrorlnfo 接口的使用示例

[翻译] WPF 中用户控件 DataContext/Binding 和依赖属性的问题

OxyPlot 导出图片及 WPF 元素导出为图片的方法

让 WPF 的 RadioButton 支持再次点击取消选中的功能

WPF DataGrid 如何将被选中行带到视野中

WPF 触屏事件后触发鼠标事件的问题及 DataGrid 误触问题

WPF DataGrid 通过自定义表头模拟首行固定

WPF ComboBox 使用 ResourceBinding 动态绑定资源键并支持语言切换

【翻译】WPF 中附加行为的介绍 Introduction to Attached Behaviors in WPF

WPF 使用 Expression Design 画图导出及使用 Path 画图

WPF MVVM 弹框之等待框

解决 WPF 绑定集合后数据变动界面却不更新的问题(使用 ObservableCollection)

WPF 消息框 TextBox 绑定新数据时让光标和滚动条跳到最下面

真・WPF 按钮拖动和调整大小

WPF MVVM 模式下的弹窗

WPF 让一组 Button 实现 RadioButton 的当前样式效果

WPF 原生绑定和命令功能使用指南

WPF 用户控件的自定义依赖属性在 MVVM 模式下的使用备忘

在WPF的MVVM模式中使用OCX组件

C#

C# 实现时间来到新的一天时触发事件

C# 字符串排序时指定偏好的排列顺序

对于 C# 中 Task 的 StartNew 与 WhenAll 相互配合的实验

【问题】为什么 System.Timers.Timer 更改间隔时间后的第一次触发时间是设定时间的三倍?

C#10 新特性 [调用方参数表达式] 解决了我七年前的困惑

【分享】C# 字节帮助类 ByteHelper

C# 在自定义的控制台输出重定向类中整合调用方信息

C# 枚举转列表

.NET

Windows 服务 同时启动多个服务

PostSharp 中 AOP 功能的简单使用

.NET SDK-Style 项目(Core、Standard、.NET5)中的版本号

将 .NET Framework 项目转换为 .NET Standard 项目

ASP.NET Core MVC 网站学习笔记

Unity 容器简单使用方法

Unity容器依赖注入之属性注入使用备忘

添加服务引用来使用WebService

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值