WPF 模板

news/2024/11/17 4:56:34/文章来源:https://www.cnblogs.com/ywtssydm/p/18362936

一、数据模板
继承了ItemConrol的控件对象(如ListView、ListBox、DataGrid、TabControl等等),都可以使用数据模板DataTemplate。

数据模板的作用在于决定每个Item中的数据的展示形式。

普通控件通过Template属性来定义模板,而子项容器控件则通过ItemTemplate属性来定义子项模板。

先创建作为数据源对象的类

public class Person
{public string Name { get; set; }public int Age { get; set; }public int Gender { get; set; }public double Left { get; set; }public double Top { get; set; }
}

在xaml中定义数据集合,然后在子项容器控件中通过ItemTemplate属性定义子项数据模板。

<Window ......xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:local="clr-namespace:WPFStudy"......><Window.Resources><!--数据集合--><x:Array Type="local:Person" x:Key="persons"><local:Person Name="Hello" Age="20" Gender="1" Left="10" Top="50"/><local:Person Name="Schuyler" Age="21" Gender="2"/><local:Person Name="Cai" Age="22" Gender="1" Left="100" Top="250"/></x:Array>  </Window.Resources><Grid><ItemsControl ItemsSource="{StaticResource persons}"><ItemsControl.ItemTemplate><DataTemplate><Grid><Grid.ColumnDefinitions><ColumnDefinition/><ColumnDefinition/><ColumnDefinition/><ColumnDefinition/><ColumnDefinition/></Grid.ColumnDefinitions><TextBlock Text="{Binding Name}"/><TextBlock Text="{Binding Age}" Grid.Column="1"/><TextBlock Text="{Binding Gender}" Grid.Column="2"/><TextBlock Text="{Binding Left}" Grid.Column="3"/><TextBlock Text="{Binding Top}" Grid.Column="4"/></Grid></DataTemplate></ItemsControl.ItemTemplate></ItemsControl></Grid>
</Window>

二、子项容器模板

数据模板决定了数据的展示形式,而子项容器模板则决定了数据模板的展示形式。

子项容器模板可以通过子项容器控件的ItemsPanel进行设置。

<Window.Resources><!--数据集合--><x:Array Type="local:Person" x:Key="persons"><local:Person Name="Hello" Age="20" Gender="1" Left="10" Top="50"/><local:Person Name="Schuyler" Age="21" Gender="2"/><local:Person Name="Cai" Age="22" Gender="1" Left="100" Top="250"/></x:Array>  
</Window.Resources><Grid><ItemsControl ItemsSource="{StaticResource persons}"><!--这里是子项容器模板--><ItemsControl.ItemsPanel><ItemsPanelTemplate><Canvas/></ItemsPanelTemplate></ItemsControl.ItemsPanel><!--这里是数据模板--><ItemsControl.ItemTemplate><DataTemplate><Grid Canvas.Top="{Binding Top}" Canvas.Left="{Binding Left}"><Grid.ColumnDefinitions><ColumnDefinition/><ColumnDefinition/><ColumnDefinition/><ColumnDefinition/><ColumnDefinition/></Grid.ColumnDefinitions><TextBlock Text="{Binding Name}"/><TextBlock Text="{Binding Age}" Grid.Column="1"/><TextBlock Text="{Binding Gender}" Grid.Column="2"/><TextBlock Text="{Binding Left}" Grid.Column="3"/><TextBlock Text="{Binding Top}" Grid.Column="4"/></Grid></DataTemplate></ItemsControl.ItemTemplate></ItemsControl>
</Grid>

数据模板决定了每个Item中的数据怎么展示出来,而子项容器模板则决定了每个Item怎么展示出来。

如上述代码所示,会将ItemsControl的每个Item按序放入到Canvas中,由于Canvas的每个子元素都以左上角为原始坐标,所以堆在左上角了。

需要注意的是,在上述代码中数据模板的Grid设置了Canvas.Top和Canvas.Left属性值,但却没有效果,这是因为这两个属性只针对Canvas的直接子元素起作用。
然而ItemControl的数据模板中的容器对象(这里是Grid)并不是直接放置到子项容器模板的容器对象(这里是Canvas)中的,而是先将Grid放入到ContentPresenter元素后,
再将ContentPresenter元素放置到Canvas中。因此正确的做法应该是在ItemsControl的ItemContainerStyle属性中对ContentPresenter进行样式设置。
<Grid><ItemsControl ItemsSource="{StaticResource persons}"><!--应该在这里编写子项容器样式--><ItemsControl.ItemContainerStyle><Style TargetType="ContentPresenter"><Setter Property="Canvas.Top" Value="{Binding Top}"/><Setter Property="Canvas.Left" Value="{Binding Left}"/></Style></ItemsControl.ItemContainerStyle>......</ItemsControl>
</Grid>

完整的渲染过程(ItemsControl中的ItemsPresenter与ContentPresenter)
为了便于理解,这里简单描述一下ItemsControl的渲染过程,顺便缕一缕ItemsPresenter与ContentPresenter在ItemsControl控件中的作用

ItemsControl在渲染时,使用一个名为 ItemsPresenter 的控件来展示各个子项,主要用来控制如何布局(使用ItemsPanelTemplate中设定的容器)和显示这些子项,但它不是用于承载单个子项内容的控件。
ItemsControl在渲染时,会使用ContentPresenter控件来展示单个子项内容,并且ContentPresenter会放置子项容器中(使用ItemsPanelTemplate中设定的容器)

注意,并不是所有控件都是将子项放入ContentPresenter元素中的,例如ListView就是将子项放入ListViewItem中再放入子项容器模板的容器对象中的,ComboBox则是放入到ComboBoxItem中然后再放入到容器对象中的,在使用时可以配合snoop软件进行查看。

三、层级数据模板
继承了ItemsControl的控件,除了可以使用上面说的DataTemplate数据模板外,还可以使用继承DataTemplate的层级数据模板HeaderedItemsControl,该模板对象一般用于TreeView和Menu等具有层级关系的子项容器控件中。TreeView和Menu控件都是通过ItemTemplate属性来定义层级数据模板。

public class Menu
{public string Header { get; set; }public int Index { get; set; }public ObservableCollection<Menu> Children { get; set; }
}
public class MainWindowViewModel
{public ObservableCollection<Menu> Menus { get; set; }public MainWindowViewModel(){Menus = new ObservableCollection<Menu> { new Menu{Header = "系统配置",Index = 0,Children = new ObservableCollection<Menu>{ new Menu{Header="用户设置", Index=0},new Menu{Header="权限设置", Index=1}}},new Menu{Header = "样式配置",Index=1,Children = new ObservableCollection<Menu>{new Menu{Header="主题", Index=0},new Menu{Header="图片", Index=1}}}};}
}
<Window ......><Window.DataContext><local:MainWindowViewModel/></Window.DataContext><Grid HorizontalAlignment="Center" VerticalAlignment="Center"><TreeView ItemsSource="{Binding Menus}"><TreeView.ItemTemplate><HierarchicalDataTemplate ItemsSource="{Binding Children}"><Grid><Grid.ColumnDefinitions><ColumnDefinition/><ColumnDefinition/></Grid.ColumnDefinitions><TextBlock Text="{Binding Index}"/><TextBlock Text="{Binding Header}" Grid.Column="1"/></Grid></HierarchicalDataTemplate></TreeView.ItemTemplate></TreeView></Grid>
</Window>

四、资源中的数据模板与容器模板
上面的例子中是将数据模板与子项容器模板直接使用在控件中,通过子项容器控件(继承了ItemControl的控件)的ItemTemplate和ItemsPanel属性来进行设置的(内联的用法),样式则是通过子项容器控件的ItemContainerStyle属性来设置。而数据模板、容器模板、子项容器样式的内容与控件模板的内容一样,都可以放置在<Window.Resources>作为资源来使用。

因此,上面的例子可以写成下面的形式:

<Window.Resources><!--数据集合--><x:Array Type="local:Person" x:Key="persons"><local:Person Name="Hello" Age="20" Gender="1" Left="10" Top="50"/><local:Person Name="Schuyler" Age="21" Gender="2"/><local:Person Name="Cai" Age="22" Gender="1" Left="100" Top="250"/></x:Array><!--数据模板--><DataTemplate x:Key="dateTemplate"><Grid><Grid.ColumnDefinitions><ColumnDefinition/><ColumnDefinition/><ColumnDefinition/><ColumnDefinition/><ColumnDefinition/></Grid.ColumnDefinitions><TextBlock Text="{Binding Name}"/><TextBlock Text="{Binding Age}" Grid.Column="1"/><TextBlock Text="{Binding Gender}" Grid.Column="2"/><TextBlock Text="{Binding Left}" Grid.Column="3"/><TextBlock Text="{Binding Top}" Grid.Column="4"/></Grid></DataTemplate><!--子项容器模板--><ItemsPanelTemplate x:Key="itemsPanelTemplate"><Canvas/></ItemsPanelTemplate><!--子项容器样式--><Style x:Key="itemContainerStyle" TargetType="ContentPresenter"><Setter Property="Canvas.Top" Value="{Binding Top}"/><Setter Property="Canvas.Left" Value="{Binding Left}"/></Style>
</Window.Resources>
<Grid><ItemsControl ItemsSource="{StaticResource persons}" ItemTemplate="{StaticResource dateTemplate}" ItemContainerStyle="{StaticResource itemContainerStyle}"ItemsPanel="{StaticResource itemsPanelTemplate}"></ItemsControl>
</Grid>

模板选择器
考虑这么一个场景,子项容器控件中,子项源为Person的数组,每个Person对象中都有年龄Age属性,现在需要在大于20岁时,使用模板A;小于等于20岁时使用模板B。这样的需求显然只靠xaml代码是难以实现的,此时可以配合C#代码,定义一个模板选择器类型,根据不同的条件返回不同的模板对象。

使用模板选择器具体有如下几个步骤

1、定义模板资源

<Window.Resources><!--数据集合--><x:Array Type="local:Person" x:Key="persons"><local:Person Name="Hello" Age="20" Gender="1" Left="10" Top="50"/><local:Person Name="Schuyler" Age="21" Gender="2"/><local:Person Name="Cai" Age="22" Gender="1" Left="100" Top="250"/></x:Array><DataTemplate x:Key="dataTemplateA"><Grid><TextBlock Text="{Binding Name}"/></Grid></DataTemplate><DataTemplate x:Key="dataTemplateB"><Grid><Grid.ColumnDefinitions><ColumnDefinition/><ColumnDefinition/></Grid.ColumnDefinitions><TextBlock Text="{Binding Name}"/><TextBlock Text="{Binding Age}" Grid.Column="1"/></Grid></DataTemplate>
</Window.Resources>

2、创建模板选择器类型

可以通过查看ItemControl控件的ItemTemplateSelector属性的定义代码,得知其类型为DataTemplateSelector,因此可以创建一个MyDataTemplateSelector类型,继承DataTemplateSelector类,并重写其SelectTemplate函数。

DataTemplate SelectTemplate(object item, DependencyObject container):此函数会接收两个参数,item参数为子项的数据对象,本例中为Person对象;container参数则为子项所在的父类容器对象。

public class MyDataTemplateSelector: DataTemplateSelector
{//模板A,可以在xaml中赋值public DataTemplate TemplateA { get; set; }//模板B,可以在xaml中赋值public DataTemplate TemplateB { get; set; }public override DataTemplate SelectTemplate(object item, DependencyObject container){var person = item as Person;if (person != null && person.Age > 20){return TemplateA;}return TemplateB;}
}

3、在控件中使用模板选择器

<Window ......>......<Grid><ItemsControl ItemsSource="{StaticResource persons}"><ItemsControl.ItemTemplateSelector><local:MyDataTemplateSelector TemplateA="{StaticResource dataTemplateA}"TemplateB="{StaticResource dataTemplateB}"/></ItemsControl.ItemTemplateSelector></ItemsControl></Grid>
</Window>

子项容器控件中除了数据模板选择器ItemTemplateSelector外,还有子项容器模板选择器ItemContainerStyleSelector。其他控件也有自己的模板选择器,比如继承了ContenteControl的控件(例如Button)都会有ContentTemplateSelector模板选择器。
来源:https://blog.csdn.net/jjailsa/article/details/135345658

 

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

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

相关文章

算法与数据结构——队列

队列 队列(queue)是一种遵循先入先出规则的线性数据结构。队列模拟了排队现象,即新来的人不断加入队列尾部,而队列头部的人逐个离开。 如图所示,我们将队列头部称为“队首”,尾部称为“队尾”,将把元素加入队列尾部的操作称为“入队”,删除队首元素的操作称为“出队”。…

AD采集卡:FMC210-1路1Gsps AD、1路2.5Gsps DA的FMC子卡 信号采集卡

FMC210-1路1Gsps AD、1路2.5Gsps DA的FMC子卡 一、板卡概述FMC-1AD2DA是我司自主研发的一款1路1G AD采集、1路2.5G DA回放的FMC子卡。板卡采用标准FMC子卡架构,可方便的与其他FMC板卡实现高速互联,可广泛用于高频模拟信号采集、雷达系统测试等场合。    二、 功能介绍 2.1 …

BAdam A Memory Efficient Full Parameter Optimization Method for Large Language Models

目录概BAdam代码Luo Q., Yu H. and Li X. BAdam: A memory efficient full parameter optimization method for large language models. arXiv preprint, 2024.概 本文介绍了一种 Block corrdinate descent (BCD) 的训练方式. BAdam当模型本身很大的时候, 训练它会成为一个很大…

Origin2024图表中如何直接移除异常点?

平时我们在使用Origin绘图后,可能会发现有一两个「异常点」,这个时候,我们可能会返回工作表,将异常的数据去除,但可能不知道是哪个数据,因为图和数据有时候不太好对应起来; 本期给大家分享做好图之后直接选择移除异常点功能,并且数据表中的数据也会相应的去除,是一个很…

vue3uniapps使用富文本mp-html插件

1. 实现效果 具体需求:顶部是搜索栏,包括搜索结果个数,目前跳到第几个,包含上一个、下一个按钮。富文本区域关键词高亮黄色,当前关键词为高亮橙色。如图2. 版本号 用到vue3 和 uniapp , mp-html 插件版本是v2.5.0, 插件地址:https://ext.dcloud.net.cn/plugin?id=805 用…

西安电子科技大学2021级计算机科学与技术专业重要成绩排名参考

从个人经历分享,所在计算机科学与技术专业的大学期间的重要成绩排名参考【非官方】,仅供选择方向参考!Hello World本文来自博客园,作者:LZHMS,转载请注明原文链接:https://www.cnblogs.com/LZHMS/p/18382071

OKR 如何激励团队有目标地工作

最近,关于90后和Z一代对为目标驱动的公司工作的渴望已经写了很多。这很可能成为围绕工作场所将如何演变的决定性叙述之一,尤其是在人才争夺战持续的情况下。 “带着目的工作 “需要的不仅仅是一个鼓舞人心的公司使命,它是每个领导者必须积极培养团队的东西。在这里,我将介绍…

查壳工具之Exeinfo PE

简介 Exeinfo PE是一款免费、专业的程序查壳软件,可以查看exe、dll程序的编译信息,开发语言,是否加壳,壳的种类以及入口地址等信息。 Exeinfo PE下载地址:https://github.com/ExeinfoASL/ASL GitHub地址打开后,直接选择Code--Download ZIP下载压缩包即可。 Exeinfo PE使用…

JavaScript 的事件循环、宏任务、微任务

JavaScrtipt 执行顺序 首先,必须要明确,在JavaScript中,所有任务都在主线程上执行。任务执行过程分为同步任务和异步任务两个阶段。异步任务的处理经历两个主要阶段:Event Table(事件表)和 Event Queue(事件队列)。Event Table存储了宏任务的相关信息,包括事件监听和相…

One-for-All:上交大提出视觉推理的符号化与逻辑推理分离的新范式 | ECCV 2024

通过对多样化基准的严格评估,论文展示了现有特定方法在实现跨领域推理以及其偏向于数据偏差拟合方面的缺陷。从两阶段的视角重新审视视觉推理:(1)符号化和(2)基于符号或其表示的逻辑推理,发现推理阶段比符号化更擅长泛化。因此,更高效的做法是通过为不同数据领域使用分…

投标流程

电脑不能安装WPS 国家电网新一代电子商务平台 (sgcc.com.cn) https://sign.utcsoft.com/utcbpc/service/download.html?q=ecp20 下载安装“供应商投标工具”

在Windows上搭建自己的Git服务器的图文教程

一、简介 以前,在别家的公司,一般早就把源代码管理工具搭建好了,很少有机会自己搭建一套。最近,公司也许要把现在不少的源码进行管理,于是我打算自己搭建源代码管理服务器。说起源代码管理,当然有很多中解决方案,我个人偏向搭建一个 Git 服务器。毕竟这个自己用的比较多…