[WPF系列]-数据邦定之DataTemplate 根据对象属性切换模板
引言
书接上回[WPF系列-数据邦定之DataTemplate],本篇介绍如何根据属性切换模板(DataTemplate)
切换模板的两种方式:
- 使用DataTemplateSelector来切换模板
- 使用DataTrigger来实现模板切换。
- 使用Style来是实现模板切换
A
DataTemplateSelectordoes not respond toPropertyChangenotifications, so it doesn't get re-evaluated when your properties change.The alternative I use is
DataTriggersthat changes theTemplatebased on a property.For example, this will draw all
TaskModelobjects using aContentControl, and theContentControl.Templateis based on theTaskStatusproperty of theTaskModel
使用DataTemplateSelector切换模板
在 DataType 属性一节中,我们讨论了您可以针对不同的数据对象定义不同的数据模板。 这在您拥有不同类型的 CompositeCollection 或不同类型的项集合时尤其有用。 在使用 DataTrigger 来应用属性值一节中,我们演示了如果您拥有相同类型的数据对象集合,您可以创建 DataTemplate,然后根据每个数据对象的属性值使用触发器来应用更改。 虽然触发器允许您应用属性值或启动动画,但是它们无法让您灵活重构数据对象的结构。 在某些情况下,可能需要您为类型相同但属性不同的数据对象创建其他 DataTemplate。
例如,当 Task 对象的 Priority 值为 1 时,您可能需要为它指定完全不同的外观,以给予您自己一个提醒。 在这种情况下,您需要创建 DataTemplate 来显示高优先级的 Task 对象。 让我们将以下 DataTemplate 添加到资源部分:
<DataTemplate x:Key="importantTaskTemplate">
<DataTemplate.Resources>
<Style TargetType="TextBlock">
<Setter Property="FontSize" Value="20"/>
</Style>
</DataTemplate.Resources>
<Border Name="border" BorderBrush="Red" BorderThickness="1"
Padding="5" Margin="5">
<DockPanel HorizontalAlignment="Center">
<TextBlock Text="{Binding Path=Description}" />
<TextBlock>!</TextBlock>
</DockPanel>
</Border>
</DataTemplate>
请注意,此示例使用 DataTemplate.Resources 属性。 DataTemplate 中的元素共享该部分中定义的资源。
若要提供逻辑以根据数据对象的 Priority 值选择要使用的 DataTemplate,需要创建 DataTemplateSelector 的子类并重写 SelectTemplate 方法。 在下面的示例中,SelectTemplate 方法提供逻辑以根据 Priority 属性的值返回适当的模板。 可以在封装 Window 元素的资源中找到要返回的模板。
using System.Windows;
using System.Windows.Controls; namespace SDKSample
{
public class TaskListDataTemplateSelector : DataTemplateSelector
{
public override DataTemplate
SelectTemplate(object item, DependencyObject container)
{
FrameworkElement element = container as FrameworkElement; if (element != null && item != null && item is Task)
{
Task taskitem = item as Task; if (taskitem.Priority == 1)
return
element.FindResource("importantTaskTemplate") as DataTemplate;
else
return
element.FindResource("myTaskTemplate") as DataTemplate;
} return null;
}
}
}
然后,我们可以将 TaskListDataTemplateSelector 声明为资源:
<Window.Resources> ... <local:TaskListDataTemplateSelector x:Key="myDataTemplateSelector"/> ... </Window.Resources>
若要使用模板选择器资源,请将其分配到 ListBox 的 ItemTemplateSelector 属性。 ListBox 为基础集合中的每一项调用 TaskListDataTemplateSelector 的 SelectTemplate 方法。 该调用会将数据对象作为项参数来传递。 然后,将由该方法返回的 DataTemplate 应用于该数据对象。
<ListBox Width="400" Margin="10"
ItemsSource="{Binding Source={StaticResource myTodoList}}"
ItemTemplateSelector="{StaticResource myDataTemplateSelector}"
HorizontalContentAlignment="Stretch"/>
使用模板选择器后,ListBox 现在如下所示:

这正是此示例要得到的结果。有关完整示例,请参见 Introduction to Data Templating Sample(数据模板化简介示例)
使用Style切换模板
<DataTemplate x:Key="personTemplate" TargetType="{x:Type local:TaskModel}">
<TextBlock Text="I'm an Open Task" />
</DataTemplate>
<DataTemplate x:Key="companyTemplate" TargetType="{x:Type local:TaskModel}">
<TextBlock Text="I'm a Closed Task" />
</DataTemplate>
<DataTemplate DataType="{x:Type local:TaskModel}"><ContentControl Content="{Binding}">
<ContentControl.Style>
<Style TargetType="ContentControl">
<Style.Triggers>
<DataTrigger Binding="{Binding AccountType}" Value="Person">
<Setter Property="ContentTemplate" Value="{StaticResource personTemplate}" />
</DataTrigger>
<DataTrigger Binding="{Binding AccountType}" Value="Company">
<Setter Property="ContentTemplate" Value="{StaticResource companyTemplate}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</DataTemplate>
上面这个例子没有给一个默认的ContentTemplate,我们可以改为:
<DataTemplate x:Key="OpenTaskTemplate" TargetType="{x:Type local:TaskModel}">
<TextBlock Text="I'm an Open Task" />
</DataTemplate>
<DataTemplate x:Key="ClosedTaskTemplate" TargetType="{x:Type local:TaskModel}">
<TextBlock Text="I'm a Closed Task" />
</DataTemplate>
<DataTemplate DataType="{x:Type local:TaskModel}">
<ContentControl Content="{Binding }">
<ContentControl.Style>
<Style TargetType="{x:Type ContentControl}">
<!-- Default Template -->
<Setter Property="ContentTemplate" Value="{StaticResource OpenTaskTemplate}" />
<!-- Triggers to change Template -->
<Style.Triggers>
<DataTrigger Binding="{Binding TaskStatus}" Value="Closed">
<Setter Property="ContentTemplate" Value="{StaticResource ClosedTaskTemplate}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</DataTemplate>
使用DataTrigger切换模板
<DataTemplate DataType="{x:Type viewModels:CorePlugViewModel}">
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ShowGridLines="True" >
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Text="{Binding Name}" Margin="4"></TextBlock>
<ContentControl x:Name="viewBox" Grid.Row="1" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<Image Source="{Binding MapThumbnail}" />
</ContentControl>
</Grid>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding HasMap}" Value="True">
<Setter Property="Template" TargetName="viewBox">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ContentControl}">
<views:CorePlugWithMap VerticalAlignment="Stretch" HorizontalAlignment="Stretch" MinHeight="10"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
如果您的 Setters 相关属性不是当前 DataTemplate 中元素的属性,则使用 Style(用于 ListBoxItem 类)设置属性更合适(如果您要绑定的控件是 ListBox)。
比较
| 方式 | 注意事项 | 适用 |
| DataTemplateSelector | 无法相应propertyChanged事件 | 静态更改模板 |
| StyleTriger | 能够动态更改绑定模板 | |
| DataTriger | Setters 相关属性不是当前 DataTemplate 中元素的属性,则使用 Style | 能够动态更改绑定模板 |
参考
Change Data template dynamically
[WPF系列]-数据邦定之DataTemplate 根据对象属性切换模板的更多相关文章
- [WPF系列]-数据邦定之DataTemplate 对分层数据的支持
到目前为止,我们仅讨论如何绑定和显示单个集合. 某些时候,您要绑定的集合包含其他集合. HierarchicalDataTemplate 类专用于 HeaderedItemsControl 类型以显示 ...
- [WPF系列]-数据邦定之DataTemplate简介
引言 WPF 数据模板化模型为定义数据的表示形式提供了很大的灵活性.WPF 控件有支持自定义数据表示形式的内置功能.首先介绍下如何定义Datatemplate,然后再介绍其他数据模板化功能,例如根据自 ...
- [WPF系列]-数据邦定之DataTemplate 使用 DataTrigger 来应用属性值
使用 DataTrigger 来应用属性值 当前表示不会告诉我们某个 Task 是家庭任务还是办公室任务.记住 Task 对象拥有类型为 TaskType 的 TaskType 属性,该类型是一个枚举 ...
- [WPF系列]-数据邦定之DataTemplate 对 ItemsControl 进行样式和模板处理
引言 即使 ItemsControl 不是 DataTemplate 所用于的唯一控件类型,将 ItemsControl 绑定到集合仍然很常见. 在 DataTemplate 中有哪些内容一节中, ...
- ASP.NET中数据邦定效率问题的一点看法 - 转载(自由的天空)
在 做Asp.NET开发的时候经常用到DataList.Repeater等,用这些控件的时候经常用到数据邦定,很多程序员都是按照MS提供的方 法<%#DataBinder.Eval(Contai ...
- js系列教程2-对象、构造函数、对象属性全解
全栈工程师开发手册 (作者:栾鹏) 快捷链接: js系列教程1-数组操作全解 js系列教程2-对象和属性全解 js系列教程3-字符串和正则全解 js系列教程4-函数与参数全解 js系列教程5-容器和算 ...
- fastreport for .net 数据邦定
C# Code: private void button4_Click(object sender, EventArgs e){ //打印主从表数据 string file = Applic ...
- [WPF系列]-ListBox
引言 本文就WPF中的ListBox常用项给以实例代码演示,包括隐蔽属性的设置,Style设置,以及ControlTemplate的自定义. Listbox平滑滚动 <ListBox Ite ...
- [WPF系列]-TreeView的常用事项
引言 项目经常会用Treeview来组织一些具有层级结构的数据,本节就将项目使用Treeview常见的问题作一个总结. DataBinding数据绑定 DataTemplate自定义 <Hier ...
随机推荐
- MySQL数据迁移到MSSQL-以小米数据库为例-测试828W最快可达到2分11秒
这里采用.NET Framework 4.0以上版本中新出现的 ConcurrentQueue<T> 类 MSDN是这样描述的: ConcurrentQueue<T> 类是一个 ...
- Asp.NET MVC 使用 SignalR 实现推送功能一(Hubs 在线聊天室)
简介 ASP .NET SignalR 是一个ASP .NET 下的类库,可以在ASP .NET 的Web项目中实现实时通信.什么是实时通信的Web呢?就是让客户端(Web页面)和服务器端 ...
- UDS(ISO14229-2006) 汉译(No.1 范围)
ISO14229指定的数据链路是独立于诊断服务的,该数据链路允许测试仪(Client)操作ECU(Server)中的诊断功能(如电子燃油喷射.变速箱.ABS等)并接入一条嵌入车辆的串行数据链路.它指定 ...
- Linux实战问题解决方案(1):Could not get lock
环境: Ubuntu12.04 问题描述: Could not get lock /var/lib/apt/lists/lock - open (11: Resource temporarily un ...
- php实现设计模式之 组合模式
<?php /** * 组合模式 * * 将对象组合成树形结构以表示"部分-整体"的层次结构,使得客户对单个对象和复合对象的使用具有一致性 * * * 1) 抽象构件角色Co ...
- Castle Windsor常用介绍以及其在ABP项目的应用介绍
最近在研究ABP项目,有关ABP的介绍请看阳光铭睿 博客,ABP的DI和AOP框架用的是Castle Windsor下面就对Castle Windsor项目常用方法介绍和关于ABP的使用总结 1.下载 ...
- JS时间戳格式化日期时间
由于mysql数据库里面存储时间存的是时间戳,取出来之后,JS要格式化一下显示.(李昌辉) 用的次数比较多,所以写了一个简单方法来转换: //时间戳转时间 function RiQi(sj) { va ...
- [Cordova] 手机网页里的1px
[Cordova] 手机网页里的1px 1px的显示 Cordova让开发人员可以使用HTML页面,来开发APP的显示内容.但是在手机上,HTML页面里定义的1px,并不是直接对应到手机屏幕的一个像素 ...
- 小记max-with与 max-device-width
max-with是浏览器的宽度,max-device-width是设备显示器的宽度 浏览器宽度不等于显示器宽度 浏览器可以缩小 1.max-device-width是设备整个显示区域的宽度,例如,真实 ...
- 使用Object.create 克隆对象以及实现单继承
var Plane = function () { this.blood = 100; this.attack = 1; this.defense = 1; }; var plane = new Pl ...