WPF 模板总结(Template)

news/2024/9/20 17:47:37
模板(Template): WPF系统不但支持传统的Winfrom编程的用户界面和用户体验设计,更支持使用专门的设计工具Blend进行专业设计,同时还推出了以模板为核心的新一代设计理念。 
在WPF中,通过引入模板(Template)微软将数据和算法的“内容”与“形式”解耦了。模板是算法和数据的外衣,决定了它们长什么样子。WPF中的模板(Template)分为两大类:ControlTemplate是算法内容的表现形式,一个控件怎样组织其内部结构才能更符合业务逻辑和需求。 DataTemplate是数据内容表现形式,决定一条数据显示成什么样子。Style(样式):设置控件样式,构成Style重要的两个元素是Setter和Trigger,Setter类帮助我们设置控件的静态外观风格,Trigger类则帮助我们设置控件的行为风格。Template与Style联系和区别:如果只需对控件进行小幅度修饰(调整大小、位置、字体、颜色等)就用style,如果需要改变控件的外观和行为就用controlTemplate(形状、事件触发如鼠标停留效果等)。
在实际项目中,经常把Template定义在Style中,通过Style 中的Property来设置控件的Template属性。
ControlTemplate控件模板主要有两个重要属性:VisualTree内容属性和Triggers触发器。所谓VisualTree(视觉树),就是呈现我们所画的控件。Triggers可以对我们的视觉树上的元素进行一些变化。
一般用于单内容控件。如设置一个圆角Button的ControlTemplate实例如下:

Note:

Style设置Key值,控件引用其Key来设置自身样式;如果Style没有设置Key值,则Style作用域内所有TargetType类型控件都默认使用其样式。
ControlPresenter 通常叫做内容占位符,用来替换ContentControl控件。如果没有ControlPresenter ,内容控件就没有内容显示(Button上的字将不显示)。
ItemsPresenter用于显示条目数据,作为条目内容占位符。 DataTemplate允许定制.NET对象的外观,也就是数据的外观,常用在以下3处:ContentControl的ContentTemplate属性,用于定制ContentControl内容的外观;
ItemsControl的ItemTemplate属性,用于定制ItmsControl数据条目的外观;GridViewColumn的CellTemplate属性,相当于定制GridViewColumn单元格数据的外观。
1.ContentTemplate使用:<Window x:Class="MainWindow"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:MainWindow"mc:Ignorable="d"Title="MainWindow" Height="150" Width="360"><Window.Resources><DataTemplate x:Key="template1"><TextBlock Text="{Binding}" FontSize="12" FontWeight="Bold" TextWrapping="Wrap"></TextBlock></DataTemplate></Window.Resources><Grid><ContentControl Name="contCtrl" ContentTemplate="{StaticResource template1}" Content="This is the content of the content control."/></Grid>
</Window>
2.ItemTemplate使用:后端代码:using System;
using System.Collections.Generic;
using System.Windows;
namespace WpfTemplate
{/// <summary>/// DataTemplateDemo.xaml 的交互逻辑/// </summary>public partial class DataTemplateDemo : Window{public List<Book> BookList { get; set; } = new List<Book>();public DataTemplateDemo(){InitializeComponent();BookList.Add(new Book() { Title = "三国演义", Author = "罗贯中",Time=DateTime.Now.AddYears(-200) });BookList.Add(new Book() { Title = "红楼梦", Author = "曹雪芹", Time = DateTime.Now.AddYears(-150) });BookList.Add(new Book() { Title = "西游记", Author = "吴承恩", Time = DateTime.Now.AddYears(-230) });}}
}
前端代码:<Window x:Class="WpfTemplate.DataTemplateDemo"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:WpfTemplate"mc:Ignorable="d"Title="DataTemplateDemo" Name="win" Height="400" Width="600"><Window.Resources><DataTemplate x:Key="MyDataTemplate"><StackPanel Orientation="Horizontal"><Border Background="Pink"><TextBlock Text="{Binding Title}"/></Border><Button Content="{Binding Author}"  Cursor="Hand" Margin="10,0"/></StackPanel></DataTemplate></Window.Resources><Grid><ListBox Grid.Row="1" ItemsSource="{Binding BookList,ElementName=win}" ItemTemplate="{StaticResource MyDataTemplate}"/></Grid>
</Window>
3.CellTemplate使用<Window x:Class="WpfTemplate.DataTemplateDemo"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:WpfTemplate"mc:Ignorable="d"Title="DataTemplateDemo" Name="win" Height="400" Width="600"><Grid><DataGrid  AutoGenerateColumns="False" ItemsSource="{Binding BookList,ElementName=win}" Grid.Row="1" Grid.Column="1"><DataGrid.Columns><DataGridTextColumn Header="书名" Binding="{Binding Title}" /><DataGridTextColumn Header="作者" Binding="{Binding Author}" /><DataGridTemplateColumn Header="时间"><DataGridTemplateColumn.CellTemplate><DataTemplate><DatePicker SelectedDate="{Binding Time}"  BorderThickness="0" /></DataTemplate></DataGridTemplateColumn.CellTemplate></DataGridTemplateColumn></DataGrid.Columns></DataGrid></Grid>
</Window>
ItemsPanelTemplate使用: ItemsPanelTemplate可以被设置为ItemsControl的ItemsPanel。例中,ItemsControl的条目显示默认是垂直排列,通过ItemsPanel属性修改为水平排列。<Grid><ListBox><!--ItemsPanel--><ListBox.ItemsPanel><ItemsPanelTemplate><StackPanel Orientation="Horizontal"/></ItemsPanelTemplate></ListBox.ItemsPanel><!--条目--><TextBlock Text="Allan"/><TextBlock Text="Kevin"/><TextBlock Text="Drew"/><TextBlock Text="Timothy"/></ListBox>
</Grid>
Template扩展:很多时候数据是以XML形式存储的,DataTemplate具有直接把XML数据结点当作目标对象的功能——XML数据中的元素名(标签名)可以作为DataType,元素的子结点和Attribute可以使用XPath来访问。下面的代码使用XmlDataProvider作为数据源,代码如下:<Window x:Class="WpfApp.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  xmlns:local="clr-namespace:WpfApp"xmlns:c="clr-namespace:System.Collections;assembly=mscorlib"Title="MainWindow" Height="500" Width="333.035"><Window.Resources><!--Data Template--><DataTemplate DataType="Unit"><Grid><StackPanel Orientation="Horizontal"><Grid><Rectangle Stroke="Yellow" Fill="Orange" Width="{Binding XPath=@Price}"/><TextBlock Text="{Binding XPath=@Year}"/></Grid><TextBlock Text="{Binding XPath=@Price}" Margin="5.0"/></StackPanel></Grid></DataTemplate><!--数据源--><XmlDataProvider x:Key="ds" XPath="Units/Unit"><x:XData><Units xmlns=""><Unit Year="2001" Price="100"/><Unit Year="2001" Price="120"/><Unit Year="2001" Price="140"/><Unit Year="2001" Price="160"/><Unit Year="2001" Price="180"/><Unit Year="2001" Price="200"/></Units></x:XData></XmlDataProvider></Window.Resources><StackPanel><ListBox ItemsSource="{Binding Source={StaticResource ds}}"/><ComboBox ItemsSource="{Binding Source={StaticResource ds}}" Margin="5"/></StackPanel>
</Window>
显示层级数据的模板HierarchicalDataTemplateXML最大的优势是可以方便地表示带有层级的数据,WPF准备了TreeView和Menultem控件用来显示层级数据,能够帮助层级控件显示层级数据的模板是HierarchicalDataTemplate。第一个例子是使用TreeView显示多层级、不同类型数据,需要为每种数据设计一个模板,有机会使每种数据类型有自己独特的外观。数据保存在项目根目录的Data.xml文件中,内容如下:<?xml version="1.0" encoding="utf-8" ?>
<Data xmlns=""><Grade Name="一年级"><Class Name="甲班">         <Group Name="A组"/><Group Name="B组"/><Group Name="C组"/></Class><Class Name="乙班"><Group Name="A组"/><Group Name="B组"/><Group Name="C组"/></Class></Grade><Grade Name="二年级"><Class Name="甲班"><Group Name="A组"/><Group Name="B组"/><Group Name="C组"/></Class><Class Name="乙班"><Group Name="A组"/><Group Name="B组"/><Group Name="C组"/></Class></Grade>
</Data>
程序的XAML代码如下:<Window x:Class="WpfApp.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"         Title="MainWindow" Height="400" Width="333.035">    <Window.Resources><!--数据源--><XmlDataProvider x:Key="ds" Source="Data.xml" XPath="Data/Grade"/><!--年级模板--><HierarchicalDataTemplate DataType="Grade" ItemsSource="{Binding XPath=Class}"><TextBlock Text="{Binding XPath=@Name}"/></HierarchicalDataTemplate><!--班级模板--><HierarchicalDataTemplate DataType="Class" ItemsSource="{Binding XPath=Group}"><RadioButton Content="{Binding XPath=@Name}" GroupName="gn"/></HierarchicalDataTemplate><!--小组模板--><HierarchicalDataTemplate DataType="Group" ItemsSource="{Binding XPath=Student}"><CheckBox Content="{Binding XPath=@Name}"/></HierarchicalDataTemplate></Window.Resources><Grid><TreeView Margin="5" ItemsSource="{Binding Source={StaticResource ds}}"/></Grid>
</Window>

第二个例子是同一种数据类型的嵌套结构,这种情况下只需设计一个HierarchicalDataTemplate,它会产生自动迭代应用的效果。数据仍然存放在Data.xml文件中,数据全都是Operation类型:<?xml version="1.0" encoding="utf-8" ?>
<Data xmlns=""><Operation Name="文件" Gesture="F"><Operation Name="新建" Gesture="N"><Operation Name="项目" Gesture="Control+P"/><Operation Name="网站" Gesture="Control+W"/><Operation Name="文档" Gesture="Control+D"/></Operation><Operation Name="保存" Gesture="S"/><Operation Name="打印" Gesture="P"/><Operation Name="退出" Gesture="X"/></Operation><Operation Name="编辑" Gesture="E"><Operation Name="拷贝" Gesture="Control+C"/><Operation Name="剪切" Gesture="Control+X"/><Operation Name="粘贴" Gesture="Control+V"/></Operation>
</Data>
 程序的XAML代码如下:<Window x:Class="WpfApp.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"         xmlns:sys="clr-namespace:System;assembly=mscorlib"Title="MainWindow" Height="300" Width="300"><Window.Resources><!--数据源--><XmlDataProvider x:Key="ds" Source="Data.xml" XPath="Data/Operation"/><!--Operation 模板--><HierarchicalDataTemplate DataType="Operation" ItemsSource="{Binding XPath=Operation}"><StackPanel Orientation="Horizontal"><TextBlock Text="{Binding XPath=@Name}" Margin="10,0"/><TextBlock Text="{Binding XPath=@Gesture}"/></StackPanel></HierarchicalDataTemplate></Window.Resources><StackPanel MenuItem.Click="StackPanel_Click"><Menu ItemsSource="{Binding Source={StaticResource ds}}"/></StackPanel>
</Window>
HierarchicalDataTemplate的作用目标是Menultem的Header,可以从被单击Menultem的Header中取出XML数据。事件处理器代码如下:private void StackPanel_Click(object sender, RoutedEventArgs e)
{MenuItem mi = e.OriginalSource as MenuItem; XmlElement xe = mi.Header as XmlElement; MessageBox.Show(xe.Attributes["Name"].Value);
}

 Note:可以维护一个CommandHelper类,根据拿到的数据来决定执行什么RoutedCommand。从外界访问Template内部的控件及其属性值由ControlTemplate或DataTemplate生成的控件都是“由Template生成的控件”,ControlTemplate和DataTemplate两个类均派生自FrameworkTemplate类,有个名为FindName的方法可以检索其内部控件。
检索ControlTemplate生成的控件
设计一个ControlTemplate并把它应用在一个UserControl上,界面上还有一个Button,在它的Click事件处理器中检索由ControlTemplate生成的代码。
程序的XAML代码如下:<Window x:Class="WpfApp.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="160" Width="300"><Window.Resources><ControlTemplate x:Key="cTmp"><StackPanel Background="Orange"><TextBox x:Name="textBox1" Margin="6"/><TextBox x:Name="textBox2" Margin="6,0"/><TextBox x:Name="textBox3" Margin="6"/></StackPanel>                  </ControlTemplate></Window.Resources><StackPanel Background="Yellow"><UserControl x:Name="uc" Template="{ StaticResource cTmp}" Margin="5"/> <Button Content="Find by Name" Width="120" Height="30" Click="Button_Click"/></StackPanel>
</Window>
后台代码如下:private void Button_Click(object sender, RoutedEventArgs e){TextBox tb = this.uc.Template.FindName("textBox1", this.uc) as TextBox;tb.Text = "Hello WPF";StackPanel sp = tb.Parent as StackPanel;(sp.Children[1] as TextBox).Text = "Hello ControlTemplate,I can find you!";}
Trigger扩展:
由数据触发的DataTrigger
基于数据执行某些判断可以考虑使用DataTrigger,DataTrigger对象的Binding属性会把数据源源不断送过来,一旦送来的值与Value属性一致DataTrigger即被触发。
下面例子中,当TextBox的Text长度小于7个字符时其Border会保持红色,XAML代码如下:<Window x:Class="WpfApp.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"    xmlns:local="clr-namespace:WpfApp"Title="MainWindow" Height="123.435" Width="204.297"><Window.Resources><local:L2BConverter  x:Key="cvtr"/><Style TargetType="TextBox"><Style.Triggers><DataTrigger Binding="{ Binding RelativeSource={x:Static RelativeSource.Self}, Path=Text.Length, Converter={ StaticResource cvtr}}" Value="false"><Setter Property="BorderBrush" Value="Red"/><Setter Property="BorderThickness" Value="1"/></DataTrigger></Style.Triggers></Style></Window.Resources><StackPanel><TextBox Margin="5"/><TextBox Margin="5,0"/><TextBox Margin="5"/></StackPanel>
 为了将控件自己作为数据源需要使用RelativeSource,如果不明确指出Source时Binding会把控件的DataContext属性当作数据源而非把控件自身当作数据源。
Binding的Path被设置为Text.Length,字符串的长度是一个具体的数字,基于这个长度值做判断时需要用到Converter,创建如下的Converter://经Converter转换后,长度值会转换成bool类型值,DataTrigger的Value被设置为false。
public class L2BConverter : IValueConverter 
{ public object Convert(object value,Type targetype,object parameter, CultureInfo culture){int textLength = (int)value; return textLength > 6 ? true : false;}public object ConvertBack(object value, Type targetype, object parameter, CultureInfo culture) {throw new NotImplementedException();}
}

多数据条件触发的MultiDataTrigger遇到要求多个数据条件同时满足时才能触发变化的需求,此时可以考虑使用MultiDataTrigger。
用户界面上使用ListBox显示了一列Student数据,当Student对象同时满足ID为2、Name为Tom的时候条目就高亮显示,示例的XAML代码如下:<Window x:Class="WpfApp.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"         Title="MainWindow" Height="123.435" Width="300"><Window.Resources><Style TargetType="ListBoxItem"><!--使用Style设置DataTemplate--><Setter Property="ContentTemplate"><Setter.Value><DataTemplate><StackPanel Orientation="Horizontal"><TextBlock Text="{Binding ID}" Width="60"/><TextBlock Text="{Binding Name}" Width="120"/><TextBlock Text="{Binding Age}" Width="60"/>                            </StackPanel></DataTemplate></Setter.Value></Setter><!--MultiDataTrigger--><Style.Triggers><MultiDataTrigger><MultiDataTrigger.Conditions><Condition Binding="{Binding Path=ID}" Value="2"/><Condition Binding="{Binding Path=Name}" Value="Tom"/></MultiDataTrigger.Conditions><MultiDataTrigger.Setters><Setter Property="Background" Value="Orange"/></MultiDataTrigger.Setters></MultiDataTrigger></Style.Triggers></Style>        </Window.Resources><StackPanel><ListBox x:Name="listBoxStudent" Margin="5"/></StackPanel>
</Window>
后台代码:public partial class MainWindow : Window
{public MainWindow(){InitializeComponent();List<Student> studentList = new List<Student>() {new Student(){ ID=1, Name="Tim", Age=21},new Student(){ ID=2, Name="Tom", Age=22 }}; this.listBoxStudent.ItemsSource = studentList;} 
}
public class Student
{public int ID { get; set; }public string Name { get; set; }public int Age { get; set; }
}

由事件触发的EventTrigger
EventTrigger是触发器中最特殊的一个,它是由事件来触发,被触发后执行一段动画,U1层的动画效果往往与EventTrigger相关联。
创建了一个针对Button的Style,这个Style包含两个EventTrigger,一个由MouseEnter事件触发,另一个由MouseLeave事件触发。XAML代码如下:<!--由事件触发的EventTrigger--><Style TargetType="Button"><Style.Triggers><!--鼠标进入--><EventTrigger RoutedEvent="MouseEnter"><BeginStoryboard><Storyboard><DoubleAnimation To="150" Duration="0:0:0.2" Storyboard.TargetProperty="Width"/><DoubleAnimation To="150" Duration="0:0:0.2" Storyboard.TargetProperty="Height"/></Storyboard></BeginStoryboard></EventTrigger><!--鼠标离开--><EventTrigger RoutedEvent="MouseLeave"><BeginStoryboard><Storyboard><DoubleAnimation Duration="0:0:0.2" Storyboard.TargetProperty="Width"/><DoubleAnimation Duration="0:0:0.2" Storyboard.TargetProperty="Height"/></Storyboard></BeginStoryboard></EventTrigger></Style.Triggers></Style>

 

来源:https://blog.csdn.net/lvxingzhe3/article/details/129941884

 

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

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

相关文章

Linux-手动扩容磁盘分区

Linux-手动扩容磁盘分区 1. 手动扩容磁盘分区 实例演示:使用 fdisk 扩容 ext4 磁盘分区 在本示例中,我们将阿里云的高效云盘从50GB扩容到60GB。 1.1 扩容前检查磁盘分区信息检查并记录分区表信息: fdisk -l /dev/vdb输出示例: Disk /dev/vdb: 60 GiB, 64424509440 bytes, 1…

Linux系统使用 mkfs.xfs 格式化磁盘分区

Linux系统使用 mkfs.xfs 格式化磁盘分区 1.安装 xfs 工具集在 CentOS 7 上安装: yum install xfsprogs -y在 Ubuntu 18 上安装: apt-get install xfsprogs在 Arch Linux 上安装: pacman -S xfsprogs2.修改磁盘分区表使用 fdisk 创建分区: fdisk /dev/vdb使用 parted 创建分…

RTX腾讯通停止服务,有哪些低成本平滑升级迁移方案?

一、RTX腾讯通继续使用的核心痛点 自RTX腾讯通停更以及官网下架,直接切断了用户获取更新、技术支持及资源下载的渠道,更迫使用户面对一系列难以忽视的严峻问题: ● 在国产系统及移动端无法使用:RTX腾讯通仅兼容Windows与MAC系统,导致用户无法在国产操作系统以及移动端使用…

[ABC263G] Erasing Prime Pairs

题目思路 看到配对,想到网络流。 考虑如果一个点是奇数,那么将源点与其连接,如果是偶数,那么将汇点与其连接,如果一对奇数和偶数的和是质数,那么将它们两对应的点相连。其中,我们要对 1 特殊处理,因为 \(1 + 1 = 2\) 而 \(2\) 是偶数且是质数,所以考虑费用流,尽可能多…

asp.net webapi 控制器中获取appsettings.json 中的数组对象

appsettings.json 文件内容: {"Logging": {"LogLevel": {"Default": "Information","Microsoft.AspNetCore": "Warning"}},"MyConfigKey": "MyConfigValue","AllowedHosts": "…

Linux系统使用 mkfs.ext4 格式化磁盘分区

Linux系统使用 mkfs.ext4 格式化磁盘分区 1.安装格式化工具大多数系统默认已经安装相关的软件工具。2.修改分区表可以使用 fdisk 或 parted 来修改分区表。3.格式化磁盘格式化指定分区: mkfs.ext4 /dev/vdb1格式化完成后进行优化配置: tune2fs -c -1 /dev/vdb14.挂载磁盘分区…

Day01-标题、字体、引用、分割线、图片、超链接、列表、表格、代码

Day01-标题、字体、引用、分割线、图片、超链接、列表、表格、代码 标题 一级标题:一个井号 空格 回车 二级标题:两个井号 空格 回车 二级标题 三级标题:三个井号 空格 回车 三级标题 ...... (最多到6级标题) 字体 Hello World!!!!!!! 斜…

2024-09-20 如何去除vue前端框架upload组件中的缓存 ==》v-if+setTimeout

在很多前端框架中的upload组件,比如arco-design的a-upload组件,在遍历渲染过程中会发现上传完成后,切换到另一个a-upload组件,它的图片会显示上一个a-upload组件的缓存 正常上传,然后点击红色,红色对应的图片应该被清空,实际上却并没有,如下解决方案:给a-upload组件加…