【WPF.NET开发】创建模板

本文内容

  1. 何时创建 ControlTemplate
  2. 先决条件
  3. 创建 ControlTemplate
  4. 使用模板
  5. 添加触发器
  6. 使用 VisualState

使用 Windows Presentation Foundation (WPF),可以使用自己的可重用模板自定义现有控件的可视结构和行为。 可以对应用程序、窗口和页面全局应用模板,也可以将模板直接应用于控件。 需要新建控件的大多数场景均可改为为现有控件创建新模板。

本文将介绍如何为 Button 控件创建新的 ControlTemplate。

1、何时创建 ControlTemplate

控件有许多属性,例如 Background、Foreground 和 FontFamily。 这些属性控制控件外观的不同方面,但可通过设置这些属性进行的更改有限。 例如,可以从 CheckBox 中将 Foreground 属性设置为蓝色,并将 FontStyle 设置为斜体。 要自定义设置控件中其他属性无法实现的控件外观时,则创建 ControlTemplate。

在多数用户界面中,按钮的总体外观相同:即一个包含某些文本的矩形。 若想要创建一个圆形的按钮,可以创建一个继承自该按钮或重新创建该按钮功能的新控件。 此外,新用户控件还会提供圆形视觉对象。

通过自定义现有控件的可视布局,可以避免创建新控件。 借助圆形按钮,可创建具有所需可视布局的 ControlTemplate。

另一方面,如果你需要具有新功能、其他属性和新设置的控件,可创建新的 UserControl。

2、先决条件

创建新的 WPF 应用程序,在 MainWindow.xaml(或选择的其他窗口)的 <Window> 元素中设置以下属性:

展开表

属性Value
TitleTemplate Intro Sample
SizeToContentWidthAndHeight
MinWidth250

将 <Window> 元素的内容设置为以下 XAML:

<StackPanel Margin="10"><Label>Unstyled Button</Label><Button>Button 1</Button><Label>Rounded Button</Label><Button>Button 2</Button>
</StackPanel>

最后,MainWindow.xaml 文件应如下所示:

<Window x:Class="IntroToStylingAndTemplating.Window1"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:local="clr-namespace:IntroToStylingAndTemplating"mc:Ignorable="d"Title="Template Intro Sample" SizeToContent="WidthAndHeight" MinWidth="250"><StackPanel Margin="10"><Label>Unstyled Button</Label><Button>Button 1</Button><Label>Rounded Button</Label><Button>Button 2</Button></StackPanel>
</Window>

如果你运行应用程序,它将如下所示:

unstyled-button.png?view=netdesktop-8.0

3、创建 ControlTemplate

声明 ControlTemplate 的最常见方法是在 XAML 文件的 Resources 部分中声明为资源。 模板是资源,因此它们遵从适用于所有资源的相同范围规则。 简言之,声明模板的位置会影响模板的应用范围。 例如,如果在应用程序定义 XAML 文件的根元素中声明模板,则该模板可以在应用程序中的任何位置使用。 如果在窗口中定义模板,则仅该窗口中的控件可以使用该模板。

首先,将 Window.Resources 元素添加到 MainWindow.xaml 文件:

<Window x:Class="IntroToStylingAndTemplating.Window2"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:local="clr-namespace:IntroToStylingAndTemplating"mc:Ignorable="d"Title="Template Intro Sample" SizeToContent="WidthAndHeight" MinWidth="250"><Window.Resources></Window.Resources><StackPanel Margin="10"><Label>Unstyled Button</Label><Button>Button 1</Button><Label>Rounded Button</Label><Button>Button 2</Button></StackPanel>
</Window>

使用以下属性集创建新的 <ControlTemplate>:

展开表

属性Value
x:Keyroundbutton
TargetTypeButton

此控制模板很简单:

  • 控件的根元素 Grid
  • 用于绘制按钮圆形外观的 Ellipse
  • 用于显示用户指定的按钮内容的 ContentPresenter
<ControlTemplate x:Key="roundbutton" TargetType="Button"><Grid><Ellipse Fill="{TemplateBinding Background}" Stroke="{TemplateBinding Foreground}" /><ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" /></Grid>
</ControlTemplate>

TemplateBinding

创建新的 ControlTemplate 时,可能仍然想要使用公共属性更改控件外观。 TemplateBinding 标记扩展将 ControlTemplate 中元素的属性绑定到由控件定义的公共属性。 使用 TemplateBinding 时,可让控件属性用作模板参数。 换言之,设置控件属性后,该值将传递到包含 TemplateBinding 的元素。

椭圆形

请注意,<Ellipse> 元素的 Fill 和 Stroke 属性绑定到了控件的 Foreground 和 Background 属性。

ContentPresenter

此外,还将 <ContentPresenter> 元素添加到了模板。 此模板专为按钮设计,因此请注意该按钮继承自 ContentControl。 此按钮会显示该元素的内容。 可以在该按钮中设置任何内容,例如纯文本,甚至其他控件。 以下两个按钮均有效:

<Button>My Text</Button><!-- and --><Button><CheckBox>Checkbox in a button</CheckBox>
</Button>

在前面的两个示例中,将文本和复选框设置为 Button.Content 属性。 设置为内容的任何内容都可通过 <ContentPresenter> 显示,这是模板的功能。

若将 ControlTemplate 应用到 ContentControl 类型(例如 Button),将在元素树中搜索 ContentPresenter。 若找到了 ContentPresenter,模板会自动将控件的 Content 属性绑定到 ContentPresenter

4、使用模板

找到本文开头声明的按钮。

<StackPanel Margin="10"><Label>Unstyled Button</Label><Button>Button 1</Button><Label>Rounded Button</Label><Button>Button 2</Button>
</StackPanel>

将第二个按钮的 Template 属性设置为 roundbutton 资源:

<StackPanel Margin="10"><Label>Unstyled Button</Label><Button>Button 1</Button><Label>Rounded Button</Label><Button Template="{StaticResource roundbutton}">Button 2</Button>
</StackPanel>

若运行项目并查看结果,将看到此按钮具有圆形背景。

styled-button.png?view=netdesktop-8.0

你可能已注意到,此按钮不是一个圆形,而是倾斜的。 由于 <Ellipse> 元素的工作方式,它始终会扩展并填充可用空间。 将此按钮的 width 和 height 属性更改为同一个值,以使圆形均衡:

<StackPanel Margin="10"><Label>Unstyled Button</Label><Button>Button 1</Button><Label>Rounded Button</Label><Button Template="{StaticResource roundbutton}" Width="65" Height="65">Button 2</Button>
</StackPanel>

styled-uniform-button.png?view=netdesktop-8.0

5、添加触发器

即使已应用模板的按钮看上去与众不同,但它的行为与任何其他按钮相同。 若按下此按钮,将触发 Click 事件。 不过,你可能已注意到,当你将鼠标移到此按钮上方时,此按钮的视觉对象不会改变。 这些视觉对象交互均由模板定义。

通过 WPF 提供的动态事件和属性系统,你可以监视特定属性是否是某个值,必要时还可重新设置模板样式。 在此示例中,你将监视按钮的 IsMouseOver 属性。 当鼠标位于控件上方时,使用新颜色设置 <Ellipse> 的样式。 此触发器类型称为 PropertyTrigger。

必须为 <Ellipse> 添加一个可引用的名称,以便于触发器起作用。 将其命名为“backgroundElement”。

<Ellipse x:Name="backgroundElement" Fill="{TemplateBinding Background}" Stroke="{TemplateBinding Foreground}" />

接下来,将新的 Trigger 添加到 ControlTemplate.Triggers 集合。 此触发器将监视 IsMouseOver 事件是否为值 true

<ControlTemplate x:Key="roundbutton" TargetType="Button"><Grid><Ellipse x:Name="backgroundElement" Fill="{TemplateBinding Background}" Stroke="{TemplateBinding Foreground}" /><ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" /></Grid><ControlTemplate.Triggers><Trigger Property="IsMouseOver" Value="true"></Trigger></ControlTemplate.Triggers>
</ControlTemplate>

接下来,将 <Setter> 添加到 <Trigger>,后者会将 <Ellipse> 的 Fill 属性更改为一种新颜色。

<Trigger Property="IsMouseOver" Value="true"><Setter Property="Fill" TargetName="backgroundElement" Value="AliceBlue"/>
</Trigger>

运行该项目。 请注意,当你将鼠标移到按钮上方时,<Ellipse> 的颜色会改变。

mouse-move-over-button.gif?view=netdesktop-8.0

6、使用 VisualState

视觉状态由控件定义和触发。 例如,当鼠标移到控件上方时,将触发 CommonStates.MouseOver 状态。 可以基于控件的当前状态对属性更改进行动画处理。 在上一部分中,当 IsMouseOver 属性为 true 时,使用 <PropertyTrigger> 将按钮的背景更改为 AliceBlue。 可改为创建一个视觉状态,来对此颜色的更改进行动画处理,以实现平稳过过渡。 

若要将 <PropertyTrigger> 转换为动画效果的可视状态,首先要从模板删除 <ControlTemplate.Triggers> 元素。

<ControlTemplate x:Key="roundbutton" TargetType="Button"><Grid><Ellipse x:Name="backgroundElement" Fill="{TemplateBinding Background}" Stroke="{TemplateBinding Foreground}" /><ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" /></Grid>
</ControlTemplate>

接下来,在控件模板的 <Grid> 根中,添加 <VisualStateManager.VisualStateGroups>,其中包含 CommonStates 的 <VisualStateGroup>。 定义两种状态:Normal 和 MouseOver

<ControlTemplate x:Key="roundbutton" TargetType="Button"><Grid><VisualStateManager.VisualStateGroups><VisualStateGroup Name="CommonStates"><VisualState Name="Normal"></VisualState><VisualState Name="MouseOver"></VisualState></VisualStateGroup></VisualStateManager.VisualStateGroups><Ellipse x:Name="backgroundElement" Fill="{TemplateBinding Background}" Stroke="{TemplateBinding Foreground}" /><ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" /></Grid>
</ControlTemplate>

触发 <VisualState> 时,将应用该状态中定义的任何动画。 为每种状态创建动画。 动画位于 <Storyboard> 元素中。 

此状态对椭圆填充进行动画处理,将其还原为控件的 Background 颜色。

  • 此状态对椭圆 Background 颜色进行动画处理,将其更改为新颜色 Yellow

    <Storyboard><ColorAnimation Storyboard.TargetName="backgroundElement" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" To="Yellow" Duration="0:0:0.3"/>
    </Storyboard>
    

现在,<ControlTemplate> 应如下所示。

<ControlTemplate x:Key="roundbutton" TargetType="Button"><Grid><VisualStateManager.VisualStateGroups><VisualStateGroup Name="CommonStates"><VisualState Name="Normal"><Storyboard><ColorAnimation Storyboard.TargetName="backgroundElement" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"To="{TemplateBinding Background}"Duration="0:0:0.3"/></Storyboard></VisualState><VisualState Name="MouseOver"><Storyboard><ColorAnimation Storyboard.TargetName="backgroundElement" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" To="Yellow" Duration="0:0:0.3"/></Storyboard></VisualState></VisualStateGroup></VisualStateManager.VisualStateGroups><Ellipse Name="backgroundElement" Fill="{TemplateBinding Background}" Stroke="{TemplateBinding Foreground}" /><ContentPresenter x:Name="contentPresenter" HorizontalAlignment="Center" VerticalAlignment="Center" /></Grid>
</ControlTemplate>

运行该项目。 请注意,当你将鼠标移到按钮上方时,<Ellipse> 的颜色会进行动画处理。

mouse-move-over-button-visualstate.gif?view=netdesktop-8.0

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

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

相关文章

LeetCode-146.LRU缓存(Python)

此题看题解 题目链接 class ListNode:def __init__(self, keyNone, valueNone):self.key keyself.value valueself.prev Noneself.next Noneclass LRUCache:def __init__(self, capacity: int):self.capacity capacityself.cache {}self.head ListNode()self.tail Li…

[Android]CheckBox复选框

在Android开发中&#xff0c;复选框&#xff08;CheckBox&#xff09;是一种常用的控件&#xff0c;用于让用户在多个选项中进行选择。它通常用于表单中&#xff0c;让用户选择多个选项或者进行多项操作。在本篇博客中&#xff0c;我们将介绍如何在Android应用中使用CheckBox控…

Unity内置的四种渲染管线简介

Unity的渲染管线&#xff08;Rendering Pipeline&#xff09;负责将游戏场景转化为可以在屏幕上显示的像素。 Unity 提供以下渲染管线&#xff08;官方文档的介绍&#xff09;&#xff1a; 内置渲染管线是 Unity 的默认渲染管线。这是通用的渲染管线&#xff0c;其自定义选项…

《Python》面试常问:深拷贝、浅拷贝、赋值之间的关系(附可变与不可变)【用图文讲清楚!】

背景 想必大家面试或者平时学习经常遇到问python的深拷贝、浅拷贝和赋值之间的区别了吧&#xff1f;看网上的文章很多写的比较抽象&#xff0c;小白接收的难度有点大&#xff0c;于是乎也想自己整个文章出来供参考 可变与不可变 讲深拷贝和浅拷贝之前想讲讲什么是可变数据类型…

Win10 使用 Nmap 扫描 Andorid 设备开放端口

Nmap Nmap 是 网络探测工具和安全/端口扫描器。 官网链接 Nmap参考指南(Man Page) 官网下载地址 Downloading Nmap Nmap 下载安装 到官网下载对应操作系统的安装包&#xff0c; 默认配置&#xff0c;一直下一步安装即可。安装过程中备份下安装路径&#xff0c;后续用到。…

九州未来大模型一体机,加速AI应用落地

2023年已接近尾声&#xff0c;对于中国人工智能产业而言&#xff0c;这一年注定成为一个重要的转折点。在不同行业中&#xff0c;人工智能的应用不断涌现&#xff0c;众多大模型如雨后春笋般涌现。然而&#xff0c;在这一发展过程中也不可避免地出现了一系列问题&#xff0c;包…

Java项目启动过程中Mybatis报错bug(多问题汇总,持续更新)

目录 前言1. Error: Method queryTotal execution error of sql2. Cause: java.sql.SQLSyntaxErrorException: Unknown column xxxxx in fiel其他前言 统计实战中关于Mybatis出错的原因 1. Error: Method queryTotal execution error of sql 执行Springboot的时候出现如下错…

vcruntime140_1.dll文件下载安装方法分享,如何安全修复vcruntime140_1.dll

遇到vcruntime140_1.dll文件遗失是用户在使用Windows操作系统时较为普遍遭遇到的一个问题&#xff0c;它归类于动态链接库&#xff08;DLL&#xff09;文件缺失的常见情形。在今天的内容里&#xff0c;我们将深入探讨如何正确地下载和安装vcruntime140_1.dll文件&#xff0c;以…

dangerouslyUseHTMLString选项来启用自定义 HTML 片段

Old&#xff1a; const msg 切换旧版成功&#xff0c;推荐 <span id"changeMsg" style"color: #47FFF1;; text-decoration: underline;">切换新版</span> 体验最新效果;const message ElMessage({customClass: site-toast,dangerouslyUseHTML…

得到山形数组的最少删除次数(LeetCode日记)

LeetCode-1671-得到山形数组的最少删除次数 题目信息: 我们定义 a r r arr arr 是 山形数组 当且仅当它满足&#xff1a; a r r . l e n g t h > 3 arr.length > 3 arr.length>3存在某个下标 i i i &#xff08;从 0 开始&#xff09; 满足 0 < i < a r r…

Google推出Gemini AI开发——10年工作经验的Android开发要被2年工作经验的淘汰了?

应用程序中利用 Gemini 前言&#xff08;可略过&#xff09;、使用 Gemini Pro 开发应用程序正文、Android Studio 中构建Gemini API Starter 应用第 1 步&#xff1a;在 AI 的新项目模板的基础上进行构建第 2 步&#xff1a;生成 API 密钥第 3 步&#xff1a;开始原型设计 正文…

Mybatis之增删改查

目录 一、引言 二、Mybatis——增 举例&#xff1a;添加用户 三、Mybatis——删 举例&#xff1a;删除用户 四、Mybatis——改 举例&#xff1a;修改用户 五、Mybatis——查 六、注意 END&#xff1a; 一、引言 书接上回&#xff0c;我们在了解完mybatis之后&#xff0c;肯…

STM32F4 HAL流水灯Proteus仿真

源码下载&#xff1a;https://download.csdn.net/download/zlkk00/88654405

CSS基础小练习

<!DOCTYPE html> <html><head><meta charset"UTF-8"><title>圣诞节快乐</title><style>/*设置背景色*/body{background-image:linear-gradient(green 50%,red 50%);background-size:100% 30px;}/*让div在页面居中*/#text{…

ubuntu 18/20/22 安装 mysql 数据库

这里写自定义目录标题 ubuntu 18/20/22 安装 mysql 数据库1. 准备2. 安装 mysql3. 配置4. 测试 demo 用户5 服务管理5.1 查看服务状态5.2 启动服务5.3 停止服务5.4 重启服务 ubuntu 18/20/22 安装 mysql 数据库 1. 准备 安装前需要知道 root 用户的密码 假如不知道 root 用户…

20231223使用Rockchip原厂的Android11调通Firefly的AIO-3399J开发板上的AP6356S

20231223使用Rockchip原厂的Android11调通Firefly的AIO-3399J开发板上的AP6356S 2023/12/23 14:14 开发板&#xff1a;Firefly的AIO-3399J【RK3399】 SDK&#xff1a;rk3399-android-11-r20211216.tar.xz【Android11】 Android11.0.tar.bz2.aa【ToyBrick】 Android11.0.tar.bz2…

C# Onnx yolov8n csgo player detection

目录 效果 模型信息 项目 代码 下载 C# Onnx yolov8n csgo player detection 效果 模型信息 Model Properties ------------------------- date&#xff1a;2023-12-22T15:01:08.014205 author&#xff1a;Ultralytics task&#xff1a;detect license&#xff1a;AGPL-…

学会这套Pytest接口自动化测试框架,击败99%的人

Pytest 的下载安装 1、Python3 使用 pip install -U pytest 安装 2、查看 pytest 版本信息 pytest --version 3、pytest 用例的执行规则&#xff1a; ①测试文件以 test_xx.py 命名需要以 test_开头&#xff08;或_test 结尾&#xff09; ②测试类以 Test_开头&#xff0…

QtRO(Qt Remote Objects)分布式对象远程通信

一、什么是QtRO Qt Remote Objects&#xff08;QRO&#xff09;是Qt提供的一种用于实现远程对象通信的机制。 QtRO支持两种类型的通信&#xff1a;RPC&#xff08;远程过程调用&#xff09;和LPC&#xff08;本地进程通信&#xff09;。 RPC&#xff08;远程过程调用&#xf…

智能优化算法应用:基于骑手优化算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于骑手优化算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于骑手优化算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.骑手优化算法4.实验参数设定5.算法结果6.…