WPF——Control与Template理解

文章目录

  • 一、前言
  • 二、控件
  • 三、模板
    • 3.1 DataTemplate
    • 3.2 ControlTemplate
    • 3.3 ContentPresenter
  • 四、结语


一、前言

最近又翻看了下刘铁猛的《深入浅出WPF》,发现对模板章节中的部分内容有了更深的体会,所以写篇文扯扯。

文章标题是Control与Template,翻译成控件与模板。
将两者放一起不是无缘无故的,在WPF中,两者关系相当密切。


二、控件

如果有人问你什么是控件,你会怎么回答?
像界面上的按钮、文本框、滚动条啊,都是控件。
所以控件可以理解为界面的组成元素。

以上是我之前的回答,这样的回答没啥问题,很直观,很多人听了都能明白,虽然可能不太严谨。

不过如果继续问,
那为什么叫控件,而不是其它名称。这种界面上的可交互的图案,称作图形元素,不是更直观、更贴切?

我可能会回答,控件这个名称是根据Control这个单词翻译过来的,所以叫控件。

对面可能继续问,那为什么英文叫Control,而不是Graphic Element。
此时我陷入了沉思,确实,为什么会用Control这个单词来命名呢。

如何消除这个疑惑,最简单的就是百度,

百度词条
控件是指对数据和方法的封装
控件可以有自己的属性和方法,其中属性是控件数据的简单访问者,方法则是控件的一些简单而可见的功能、控件创建过程包含设计、开发、调试工作,然后是控件的使用。

先别管百度说的是对是错,但显然并不直观。你跟非程序员这么解释,他可能还是不懂。

那么从专业的角度来看,这段对控件的描述有没有道理呢。
学过程序的都知道,程序的本质是数据结构与算法

界面上的控件呈现了一定内容,并且提供了一些交互方式,用户通过交互可以改变程序状态。

那么,控件呈现的内容本质是什么?
是数据。
控件提供的交互方式本质/目的是什么?
我想应该是程序逻辑,比如你按下按钮,最终程序内部会执行一个方法(一段代码,即程序逻辑),程序状态可能会因此发生一些改变。

所以,控件既是数据的表现形式,以让用户可以直观地看到数据;又是算法的表现形式,以让用户方便地操作逻辑

作为“表现形式”,每个控件都是为了实现某种用户操作算法和直观显示某种数据而生的,一个控件看上去是什么样子由它的“算法内容”和“数据内容”决定,这也是哲学中常说的内容决定形式

这样看来,百度的这段话还是挺有道理的,更接近控件的本质。


三、模板

接下来回到WPF中的模板。

在以往的GUI技术中,控件内部的逻辑和数据是固定的,程序员不能改变(比如WinForms/Qt(QWidget));对于控件的外观,程序员能做的改变也非常有限,一般就是设置控件的属性,想改变控件的内部结构更是不可能。如果想扩展一个控件的功能或更改其外观让其更适合业务逻辑,哪怕只有一丁点改变,也经常要创建控件的子类或创建用户控件(UserControl)。造成这个局面的根本原因就是数据和算法的“形式”与“内容”耦合的太紧了

在WPF中,通过引入模板(Template),将数据和算法的“内容”和“形式”解耦了。

WPF中的Template分为两大类:

  • ControlTemplate,是算法内容的表现形式,一个控件怎样组织其内部结构才能让它更符合业务逻辑、让用户操作起来更舒服就是由它来控制的。它决定了控件“长成什么样子”,并让程序员有机会在控件原有的内部逻辑基础上扩展自己的逻辑。
  • DataTemplate,是数据内容的表现形式,一条数据显示成什么样子,是简单文本还是直观的图形动画就由它来决定。

一言蔽之,Template就是“外衣”——ControlTemplate是控件的外衣,DataTemplate是数据的外衣。

WPF中的控件不再具有固定的形象,仅仅是算法内容和数据内容的载体。
你可以把控件理解为一组操作逻辑穿上了一套衣服,换套衣服就能变成另外一个模样。你看到的控件默认形象实际上就是出厂时微软为它穿上的默认服装。

3.1 DataTemplate

在实际项目中,DataTemplate相较于ControlTemplate,往往是用的比较多一些。

正如其名,它是数据的模板/外观。使用时,往往会在外层绑上一个对象,然后在内部将对象的属性绑定到各种控件。

只要将绑定的控件更换,显示的外观也会发生变化。即一样的内容可以用不同形式来展现,软件设计称之为“数据-视图”(Data-View)模式

在WPF开发中,DataTemplate常用的地方有三处,分别是:

  • ContentControl的ContentTemplate属性,相当于给ContentControl的内容穿衣服。
  • ItemsControl的ItemTemplate属性,相当于给ItemsControl的数据项穿衣服。
  • GridViewColumn的CellTemplate属性,相当于给GridViewColumn单元格里的数据穿衣服。

3.2 ControlTemplate

前面说过,
你看到的控件默认形象实际上就是出厂时微软为它穿上的默认服装。
因为ControlTemplate有默认服装,且大部分时候默认服装已经够用了,所以很少有人会手动去修改它。

实际项目中,即使要给ControlTemplate做替换,也往往是用成熟的UI工具包,引入项目中,应用其样式即可。

这很合理,前面也说了,每个控件都是为了实现某种用户操作算法和直观显示某种数据而生的。而这些特定的操作算法是由控件的本质决定的,显然这部分内容较数据来讲是更为固定,交由微软或者专业的组件开发商决定没有问题。

不过,这也并不意味着普通程序员就完全不需要去了解ControlTemplate。因为某些时候,确实也会需要修改它们。

《WPF深入浅出》一书中说到,

实际项目中,ControlTemplate主要由两大用处:

  1. 通过更换ControlTemplate改变控件外观,使之具有更优的用户体验及外观。
  2. 接触ControlTemplate,程序员与设计师可以并行工作,程序员可以先用WPF标准控件进行编程,等设计师工作完成后,只需把新的ControlTemplate应用到程序中就可以了。

不过考虑到国内WPF开发的现状,应该很少有设计师和程序员工作完全分离的。所以ControlTemplate的使用上也集中在第一点了。

但第一点,听起来似乎和之前所说的冲突了,ControlTemplate不是呈现算法的吗,怎么变成改变控件外观的了。

其实这并不矛盾,因为控件的外观和控件的本质息息相关。

  • Button为什么形状都差不多,一般就是一个椭圆或矩形,可点击,点击后会凹下去。
  • TextBox为什么都是一个矩形框,里面可输入文字。
  • ScrollBar为什么都是一个长条,你可以拖动它移动。

还记得算法是什么吗?
每本编程入门书都会说,算法是解决问题的办法。

这些控件之所以有这样的外观和交互方式,并不是凭空产生的,而是人设计出来的。显然这样的设计就是为了解决一类问题,即它是一种算法。

当你对控件效果不满意时,就可能需要更改其外观,以贴合实际需求。

此时,我对ControlTemplate又有了一层理解。控件模板描述的是控件外观以及外观对外界刺激所做出的反应(比如各种事件/按钮鼠标触摸后的背景色变化等),而外观和对刺激的反应更深层的含义是该类控件要解决的问题的解决方案

下面是一个实际开发中的ControlTemplate应用场景,我需要在鼠标移动到按钮上时,按钮的背景色发生变红色(这是为了使鼠标移动到按钮的操作有反馈感):

<Style TargetType="Button"><Style.Triggers><Trigger Property="IsMouseOver" Value="True"><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="Button"><Border Background="red"><ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center"/></Border></ControlTemplate></Setter.Value></Setter></Trigger></Style.Triggers>
</Style>

如代码所示,用触发器检验鼠标是否在控件上,若是则修改其控件模板,主要就是将控件模板外的border的背景色变红。

3.3 ContentPresenter

实际上Button的结构就是这么简单,
在这里插入图片描述

<Border><ContentPresenter/>
</Border>

一个边框加一个ContentPresenter就组成了一个按钮。
那么,ContentPresenter是什么?
我们可以通过反编译看到其中结构,下面是我整理出来的一个类关系图:

在这里插入图片描述
你会发现ContentPresenter的结构和ContentControl高度重合。
这边我也不卖关子,也不想花太多篇幅去深究它们的关系。
你可以把ContentPresenter直接理解成控件的数据内容模板DataTemplate。

有的控件继承了ContentControl,我称之为内容控件。
也有部分控件没有继承它,比如TextBox,
在这里插入图片描述

也因此,TextBox的默认控件模板中不存在ContentPresenter。这也很好理解,都没有数据内容,何来数据内容呈现?

你可能会问,那它的Text属性不是数据内容?
当然是,但从控件的角度来看,Text这样的属性已经是相当基础了,就是一段字串(有点类似于“原子数据”),而内容控件的Content可能是有分割必要的,比如Button中可能会有文字描述/图标等。因此我个人倾向于,Text本身这种简单的特性导致了它不作为内容模板出现。


四、结语

写了这么多,主要就是谈了谈对控件以及两个模板的理解。
这种理解更像是WPF开发(也不限于WPF)的内功,不对写代码直接产生效率提升,但会有长远的积极影响。

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

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

相关文章

企业级数据仓库-理论知识

D3 AM 大数据中间件 Hive&#xff1a;将SQL转化成分布式Map/Reduce进行运算&#xff0c;也支持转换成Spark,需要单独安装Hive集群才能访问Spark,支持60%的SQL&#xff0c;延迟比较大。SparkSQL:属于Spark生态圈&#xff0c;Hive on Sqark。HBase: NoSQL,高并发读&#xff0c;适…

c语言进阶部分详解(指针进阶1)

大家好&#xff01;指针的初阶内容我已经写好&#xff0c;可移步至我的文章&#xff1a;c语言进阶部分详解&#xff08;指针初阶&#xff09;_总之就是非常唔姆的博客-CSDN博客 基本内容我便不再赘述&#xff0c;直接带大家进入进阶内容&#xff1a; 目录 一.字符指针 1.讲解…

Mac 安装软件各种报错解决方案

Mac 安装软件各种报错解决方案 文章目录 Mac 安装软件各种报错解决方案一. 打开允许“允许任何来源”二. 无法打开"xxx"&#xff0c;因为它不是从App Store下载三. 无法打开"xxx"&#xff0c;因为 Apple无法检查其是否包含恶意软件。四. "xxx"已…

【入门篇】ClickHouse最优秀的开源列式存储数据库

文章目录 一、什么是ClickHouse&#xff1f;OLAP场景的关键特征列式数据库更适合OLAP场景的原因输入/输出CPU 1.1 ClickHouse的定义与发展历程1.2 ClickHouse的版本介绍 二、ClickHouse的主要特性2.1 高性能的列式存储2.2 实时的分析查询2.3 高度可扩展性2.4 数据压缩2.5 SQL支…

C语言——通讯录管理系统

通讯录管理系统项目简介 功能说明 控制台黑窗口实现程序需要满足以下几个功能 程序开始运行时首先显示选择菜单界面&#xff0c;根据用户输入确定实现何种功能 程序界面 代码实现 多文件实现 和之前写的实战项目类似&#xff0c;这里同样采用多文件实现的方式 多文件写代码…

各种电机驱动原理

步进电机 步进电机参考资料 野火官方文档 步进电机驱动原理 上面参考文档中有的内容就不写了&#xff0c;写一下我自己的总结吧。 说明&#xff1a; 电机驱动器输入信号有电机转动方向信号DIR&#xff0c;电机转速信号PWM&#xff0c;电机使能信号EN&#xff1b;电机驱动器…

S7-1200PLC和LED电子看板通信(TCP/IP)

S7-200SMART PLC和LED电子看板通信应用,请查看下面文章链接: SMART 200 PLC UDP通讯应用LED看板_RXXW_Dor的博客-CSDN博客开放式用户通信 (OUC) 库:数据解析:https://rxxw-control.blog.csdn.net/article/details/121424897这篇博客我们主要介绍S7-1200PLC和LED电子看板通…

servlet 引用src目录下子目录的class文件方法

1、MyServlet class文件所处的目录结构如下&#xff1a; 2、如果在url里直接引用是不行的&#xff0c;http://localhost:9092/GetRequest_Web_exploded/MyServlet 3、需要在web.xml映射后才行&#xff1a; MyServlet com.example.MyServlet <servlet-mapping><ser…

HI_NAS linux 记录

dev/root 100% 占用解决记录 通过下面的命令查看各文件夹 大小 sudo du --max-depth1 -h # 统计当前文件夹下各个文件夹的大小显示为M 最终发现Var/log 占用很大空间 发现下面两个 log 占用空间很大&#xff0c;直接 rm-rf 即可 HI NAS python3 记录 # 安装pip3 sudo apt u…

Linux下C语言使用 netlink sockets与内核模块通信

netlink简介 Netlink套接字是用以实现用户进程与内核进程通信的一种特殊的进程间通信(IPC) ,也是网络应用程序与内核通信的最常用的接口。在Linux标准内核中&#xff0c;系统默认集成了很多netlink实例&#xff0c;比如日志上报、路由系统等&#xff0c;netlink消息是双向的&a…

【golang】调度系列之P

调度系列 调度系列之goroutine 调度系列之m 在前面两篇中&#xff0c;分别介绍了G和M&#xff0c;当然介绍的不够全面&#xff08;在写后面的文章时我也在不断地完善前面的文章&#xff0c;后面可能也会有更加汇总的文章来统筹介绍GMP&#xff09;。但是&#xff0c;抛开技术细…

移动端APP测试-如何指定测试策略、测试标准?

制定项目的测试策略是一个重要的步骤&#xff0c;可以帮助测试团队明确测试目标、测试范围、测试方法、测试资源、测试风险等&#xff0c;从而提高测试效率和质量。本篇是一些经验总结&#xff0c;理论分享。并不是绝对正确的&#xff0c;也欢迎大家一起讨论。 文章目录 一、测…

使用Linkerd实现流量管理:学习如何使用Linkerd的路由规则来实现流量的动态控制

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

Mac 错误zsh: command not found: brew解决方法

打开iterm或其他shell终端&#xff0c;执行命令&#xff1a; /bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)" 选择下载brew的源&#xff0c;输入1~6任意都行 根据提示输入Y及开机密码 最后执行&#xff1a;source ~/.z…

什么是鉴权?一篇文章带你了解postman的多种方式

一、什么是鉴权&#xff1f; 鉴权也就是身份认证&#xff0c;就是验证您是否有权限从服务器访问或操作相关数据。发送请求时&#xff0c;通常必须包含相应的检验参数以确保请求具有访问权限并返回所需数据。通俗的讲就是一个门禁&#xff0c;您想要进入室内&#xff0c;必须通过…

一个Qt鼠标透传场景与事件过滤器的用法

一个Qt鼠标透传场景与事件过滤器的用法 最近工作中遇到一个开发场景&#xff0c;将一个QWidget控件&#xff08;称为控件A&#xff09;放入QScrollArea&#xff0c;该控件A重写了QWidget::wheelEvent&#xff0c;根据鼠标滚轮事件缩放内部的绘制视图。当控件过大时&#xff0c…

【Redis】深入探索 Redis 主从结构的创建、配置及其底层原理

文章目录 前言一、对 Redis 主从结构的认识1.1 什么是主从结构1.2 主从结构解决的问题 二、主从结构创建2.1 配置并建立从节点2.2.1 从节点配置文件2.2.2 启动并连接 Redis 主从节点2.2.3 SLAVEOF 命令2.2.4 断开主从关系 2.2 查看主从节点的信息2.2.1 INFO REPLICATION 命令2.…

(leetcode)单值二叉树

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 目录 题目&#xff1a; 思路&#xff1a; 代码&#xff1a; 画图与分析&#xff1a; 题目&#xff1a; 如果二叉树每个节点都具有相同的值&#xff0c;那么该二叉树就是单值二叉树。 只有给定的树是单值二叉树时&…

【第四阶段】kotlin语言的构造函数学习

1.主构造函数 package Kotlin.Stage4 //主构造函数&#xff0c;规范来说&#xff0c;都是增加_xxx的形式&#xff0c;临时的输入类型&#xff0c;不能直接用。需要接收下来&#xff0c;成为变量才能用。 class TestBase(_name:String,_sex:Char,_age:Int,_info:String){ //主…

深入理解算法的时间复杂度

文章目录 时间复杂度的定义时间复杂度的分类时间复杂度分析常见数据结构和算法的时间复杂度常见数据结构常见算法 常见排序算法说明冒泡排序(Bubble Sort)快速排序(Quick Sort)归并排序(Merge Sort)堆排序(Heap Sort) 时间复杂度的定义 时间复杂度就是一种用来描述算法在输入规…