【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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

编译opencv和opencv_contrib

1 下载源码 下载opencv源码https://github.com/opencv/opencv 下载opencv源码https://github.com/opencv/opencv_contrib 2 开始编译 构建需要下载ffmpeg的包&#xff0c;cmake构建时会自动下载&#xff0c;但是比较满&#xff0c;这里可以从下面链接直接下载 https://downloa…

Linux-Keepalived(VRRP协议)高可用集群搭建

Linux-Keepalived&#xff08;VRRP协议&#xff09;高可用集群搭建 一、VRRP简介1.1 什么是VRRP&#xff1f;1.2 keepalived是什么&#xff1f;1.3 keepalived工作原理 二、实操配置过程2.1 试验模型2.2. Keepalived监控和维护VRRP集群的步骤2.2.1 安装keepalived2.2.2 配置kee…

使用OpenCV DNN模块进行人脸检测

内容的一部分来源于贾志刚的《opencv4应用开发、入门、进阶与工程化实践》。这本书我大概看了一下&#xff0c;也就后面几章比较感兴趣&#xff0c;但是内容很少&#xff0c;并没有想像的那种充实。不过学习还是要学习的。 在实际工程项目中&#xff0c;并不是说我们将神经网络…

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

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

【优化】XXLJOB修改为使用虚拟线程

【优化】XXLJOB修改为使用虚拟线程 新建这几个目录 类&#xff0c; 去找项目对应的xxljob的源码 主要是将 new Thread 改为 虚拟线程 Thread.ofVirtual().name("VT").unstarted 以下代码是 xxljob 2.3.0版本 举一反三 去修改对应版本的代码 <!-- 定…

C语言数据结构-----常用七种排序介绍、分类、实现及性能比较

前言 ①排序&#xff1a;所谓排序&#xff0c;就是使一串记录&#xff0c;按照其中的某个或某些关键字的大小&#xff0c;递增或递减的排列起来的操作。 ②稳定性&#xff1a;假定在待排序的记录序列中&#xff0c;存在多个具有相同的关键字的记录&#xff0c;若经过排序&#…

Spring中用到的设计模式

一、工厂模式 BeanFactory 1、简单工厂模型&#xff0c;是指由一个工厂对象决定创建哪一种产品类的实例&#xff0c;工厂类负责创建的对象较少&#xff0c;客户端只需要传入工厂类的参数&#xff0c;对于如何创建对象的逻辑不需要关心 优点&#xff1a; 只需传入一个正确的参数…

第四部分 一阶逻辑基本概念

目录 主要内容 一阶逻辑命题符号化 一阶逻辑公式及其解释 个体词——所研究对象中可以独立存在的具体或抽象的客体 谓词——表示个体词性质或相互之间关系的词 量词——表示数量的词 例1 用0元谓词将命题符号化 例2 在一阶逻辑中将下面命题符号化 例如 例如 例3 给定解释 I 如下…

京东JDAPI:电商行业的得力助手

一、引言 在当今电商行业中&#xff0c;数据的获取与利用显得尤为重要。作为中国领先的电商平台&#xff0c;京东提供了丰富的API接口&#xff0c;其中JD商品详情API是关键之一&#xff0c;它允许第三方开发者获取京东平台上的商品详情信息。本文将深入探讨京东JD商品详情API在…

欧洲版OpenAI疑似将在24年发布并开源GPT-4级别模型!

大家好&#xff0c;我是二狗。 今天在推特上看到一条振奋人心的消息&#xff1a; “ 欧洲版OpenAI、法国初创公司 Mistral 首席执行官 Arthur Mensch 在法国国家广播电台宣布&#xff0c;Mistral 将在 2024 年发布开源 GPT-4 级别模型。” 这位老哥接着表示甚至可能是免费的&a…

前端传输formDate格式的数据,后端不能用@RequestBody接收

写了个接口&#xff0c;跟前端对接&#xff0c;前端说怎么一直415的报错 我寻思不对啊&#xff0c;我swagger都请求成功了&#xff0c;后来发现前端一直是以formdata格式提交的数据&#xff0c;这样我其实是可以不加RequestBody的&#xff1b; 知识点&#xff1a; RequestBody…

TrustZone之与非安全虚拟化交互

到目前为止&#xff0c;我们在示例中忽略了非安全状态中可能存在的虚拟化程序。当存在虚拟化程序时&#xff0c;虚拟机与安全状态之间的许多通信将通过虚拟化程序进行。 例如&#xff0c;在虚拟化环境中&#xff0c;SMC用于访问固件功能和可信服务。固件功能包括诸如电源管理之…

将遗留系统分解为微服务:第 2 部分

在当今不断发展的技术环境中&#xff0c;从整体架构向微服务的转变对于许多企业来说都是一项战略举措。这在报销计算系统领域尤其重要。正如我在上一篇文章第 1 部分应用 Strangler 模式将遗留系统分解为微服务-CSDN博客中提到的&#xff0c;让我们探讨如何有效管理这种转变。 …

前端学习——指令

vue作为前端框架&#xff0c;为了简化或实现一些特定功能&#xff0c;提供了很多指令&#xff0c;那什么是指令呢&#xff1f; 所谓的指令就是能够完成特定功能的一些vue语法&#xff0c;比如属性绑定指令v-bind&#xff0c;事件绑定指令v-on&#xff0c;循环指令v-for等。在v…

【Amazon 实验②】使用Amazon WAF做基础 Web Service 防护之自定义规则

文章目录 1. 自定义规则1.1 介绍 2. 实验步骤2.1 测试2.2 输出 上一篇章介绍了使用Amazon WAF做基础 Web Service 防护中的Web ACLs 配置 & AWS 托管规则的介绍和演示操作 【Amazon 实验①】使用Amazon WAF做基础 Web Service 防护&#xff0c;本篇章将继续介绍关于自定义…

2009-2022年31省细分产品出口数据/按hs码分的22类细分产品的出口数据

2009-2022年31省细分产品出口数据/按hs码分的22类细分产品的出口数据 1、时间&#xff1a;2009-2022年 2、指标&#xff1a;时间、流向名称、商品编码、商品名称、伙伴名称、主题编码、方式名称、金额&#xff08;美元&#xff09; 3、来源&#xff1a;海关贸易统计数据/海关…

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

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

[SQL]实验 视图和索引的应用

实验目的&#xff1a; [实验目的和要求] 1、掌握视图的创建、修改和重命名的方法 2、掌握视图中数据的操作 3、了解索引的作用 4、掌握索引的创建方法 实验步骤&#xff1a; 1、在销售管理数据库中&#xff0c;创建一个女职工视图&#xff0c;包括员工的编号、姓名、性别、雇佣…

多标签分类中常用指标和可视化例子

多标签分类中常用指标 1. 准确率&#xff08;Accuracy&#xff09; 准确率计算的是正确预测的标签比例。对于多标签分类&#xff0c;这通常是一个较为严格的指标&#xff0c;因为要求每个实例的所有标签都预测正确。 Accuracy 正确预测的标签数 总标签数 \text{Accuracy} \…

Qt前端技术:5.QSS

这个是表示QFrame中的pushButton中的子类和它子类的子类都将背景变为red 写成大于的时候表示只有直接的子类对象才会变 这个图中的QGroupBox和QPushButton都是QFrame的直接的子类 这个中的QGroupBox是QFrame的直接的子类但是QPushButton 是QGroupBox的子类&#xff0c;QPushB…