[WP8] Binding时,依照DataType选择DataTemplate
[WP8] Binding时,依照DataType选择DataTemplate
范例下载
范例程序代码:点此下载
问题情景
在开发WPF、WP8...这类应用程序的时候,透过Binding机制搭配DataTemplate,能让数据类别在经过Binding之后于画面上呈现。例如下列的范例,透过Binding机制搭配DataTemplate,就能在WP8的ListBox控件中,依照DataTemplate的定义,来呈现Car对象集合。
执行结果

程序代码(.CS)
namespace BindingSample001.Models
{
public class Car
{
public string Name { get; set; }
}
} namespace BindingSample001
{
public partial class MainPage : PhoneApplicationPage
{
// Constructors
public MainPage()
{
// Initialize
this.InitializeComponent(); // Data
var carList = new List<Car>();
carList.Add(new Car() { Name = "C001" });
carList.Add(new Car() { Name = "C002" });
carList.Add(new Car() { Name = "C003" });
carList.Add(new Car() { Name = "C004" });
carList.Add(new Car() { Name = "C005" }); // Binding
this.ListBox001.ItemsSource = carList;
}
}
}
程序代码(.XAML)
<!--Resources-->
<phone:PhoneApplicationPage.Resources> <!--Car Template-->
<DataTemplate x:Key="CarTemplate">
<StackPanel Background="LightGreen" Margin="12,6" FlowDirection="LeftToRight">
<TextBlock Text="Car" />
<CheckBox Content="{Binding Path=Name}" />
</StackPanel>
</DataTemplate> </phone:PhoneApplicationPage.Resources> <!--LayoutRoot-->
<ListBox x:Name="ListBox001"> <!--ItemTemplate-->
<ListBox.ItemTemplate>
<StaticResource ResourceKey="CarTemplate" />
</ListBox.ItemTemplate> <!--Style-->
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</ListBox.ItemContainerStyle> </ListBox>
而在一些更复杂的开发项目中,画面上不单单只需要呈现一种的数据类别,而是需要呈现数据类别的各种延伸数据类别,并且这些不同种类的延伸数据类别,在经过Binding之后于画面上必须要有不同种类的呈现外观。例如下列的范例,Car类别为基础数据类别,Truck类别、Sedan类别各自为Car类别的延伸类别,这些Truck类别、Sedan类别在经过Binding之后,于画面上Truck类别会有一种呈现外观、而Sedan类别会有另外一种呈现外观。
本篇文章介绍如何在Binding时,依照数据类别的DataType选择对应的DataTemplate,用以在Binding之后,于画面上依照不同数据类别来呈现不同外观,为自己留个纪录也希望能帮助到有需要的开发人员。
类别结构

类别程序代码(.CS)
public class Car
{
public string Name { get; set; }
} public class Truck : Car
{
public int MaxLoad { get; set; }
} public class Sedan : Car
{
public int MaxSpeed { get; set; }
}
在WPF中,依照DataType选择DataTemplate
在WPF中,可以定义DataTemplate.DataType这个属性,用来指定DataTemplate所对应的数据类别。当定义这个属性之后,WPF应用程序在Binding时,就可以依照数据对象的DataType选择DataTemplate,并且使用这个DataTemplate的定义来呈现数据对象。例如下列的范例,Truck类别、Sedan类别在经过Binding之后,于画面上Truck类别会有一种呈现外观、而Sedan类别会有另外一种呈现外观。
执行结果

程序代码(.CS)
namespace BindingSample002
{
public partial class MainWindow : Window
{
// Constructors
public MainWindow()
{
// Initialize
this.InitializeComponent(); // Source
var carList = new List<Car>();
carList.Add(new Truck() { Name = "T001", MaxLoad = 100 });
carList.Add(new Sedan() { Name = "S002", MaxSpeed = 200 });
carList.Add(new Truck() { Name = "T003", MaxLoad = 300 });
carList.Add(new Truck() { Name = "T004", MaxLoad = 400 });
carList.Add(new Sedan() { Name = "S005", MaxSpeed = 500 }); // Binding
this.ListBox001.ItemsSource = carList;
}
}
}
程序代码(.XAML)
<!--Resources-->
<Window.Resources> <!--Truck Template-->
<DataTemplate DataType="{x:Type models:Truck}">
<StackPanel Background="LightBlue" Margin="12,6" FlowDirection="LeftToRight">
<TextBlock Text="Truck" />
<CheckBox Content="{Binding Path=Name}" />
<CheckBox Content="{Binding Path=MaxLoad}" />
</StackPanel>
</DataTemplate> <!--Sedan Template-->
<DataTemplate DataType="{x:Type models:Sedan}">
<StackPanel Background="LightPink" Margin="12,6" FlowDirection="RightToLeft">
<TextBlock Text="Sedan" />
<TextBlock Text="{Binding Path=Name}" />
<TextBlock Text="{Binding Path=MaxSpeed}" />
</StackPanel>
</DataTemplate> </Window.Resources> <!--LayoutRoot-->
<ListBox x:Name="ListBox001"> <!--Style-->
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</ListBox.ItemContainerStyle> </ListBox>
在WP8中,依照DataType选择DataTemplate
因为一些原因,在WP8中目前没有提供DataTemplate.DataType这个属性,用来指定DataTemplate所对应的数据类别,这也让WP8应用程序,没有办法提供在Binding之后,于画面上依照不同数据类别来呈现不同外观的这个功能。但是山不转路转,开发人员还是可以透过Binding机制、结合自定义的IValueConverter,来提供依照DataType选择DataTemplate这个功能。
程序代码(.XAML)

首先在页面中使用下列的XAML宣告来取代原有的DataTemplate,让DataTemplate的选择机制,改为使用Binding以及自定义的TypeTemplateConverter来提供。
程序代码(.XAML)
<!--LayoutRoot-->
<ListBox x:Name="ListBox001"> <!--ItemTemplate-->
<ListBox.ItemTemplate>
<DataTemplate>
<ContentControl Content="{Binding}" ContentTemplate="{Binding Converter={StaticResource TypeTemplateConverter}}" HorizontalContentAlignment="Stretch" />
</DataTemplate>
</ListBox.ItemTemplate> <!--Style-->
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</ListBox.ItemContainerStyle> </ListBox>
接着就是依照下列的程序代码来建立自定义的TypeTemplateConverter。这个自定义的TypeTemplateConverter实作IValueConverter,用来处理Binding的目标数据对象,并且依照目标数据对象的型别来提供DataTemplate。
这个设计直觉上会认为没有问题,但实际撰写这个Converter的时候会发现,接收目标数据对象、取得目标数据对象型别这些功能实作都没有问题,但是如何取得DataTemplate却是一个问题(范例中[???]部分的程序代码)。在TypeTemplateConverter并没有定义DataTemplate的来源,没有来源就没有办法取得DataTemplate,那当然也就没有办法依照目标数据对象型别来提供DataTemplate。
程序代码(.CS)
public sealed class TypeTemplateConverter : IValueConverter
{
// Methods
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
// Require
if (value == null) return null; // TypeName
string typeName = value.GetType().ToString(); // DataTemplate
DataTemplate dataTemplate = [???];
if (dataTemplate == null) return null; // Convert
return dataTemplate;
} public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
这时为了提供DataTemplate的来源,开发人员可以为TypeTemplateConverter类别加入System.Windows.FrameworkElement类别的继承,这样就可以使用FrameworkElement的Resources属性做为DataTemplate的来源。在这之后TypeTemplateConverter就可以使用目标数据对象型别作为索引,取得Resources属性之中的DataTemplate,用以提供Binding机制使用。
程序代码(.CS)
namespace BindingSample003.Converters
{
public sealed class TypeTemplateConverter : System.Windows.FrameworkElement, IValueConverter
{
// Methods
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
// Require
if (value == null) return null; // TypeName
string typeName = value.GetType().ToString(); // DataTemplate
var dataTemplate = this.Resources[typeName] as DataTemplate;
if (dataTemplate == null) return null; // Convert
return dataTemplate;
} public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
为TypeTemplateConverter类别加入System.Windows.FrameworkElement类别的继承之后,在XAML定义中就可以使用XAML语法来定义TypeTemplateConverter对象所要提供的DataTemplate。
程序代码(.XAML)
<!--Resources-->
<phone:PhoneApplicationPage.Resources> <!--Converter-->
<converters:TypeTemplateConverter x:Key="TypeTemplateConverter" >
<converters:TypeTemplateConverter.Resources> <!--Truck Template-->
<DataTemplate x:Key="BindingSample003.Models.Truck">
<StackPanel Background="LightBlue" Margin="12,6" FlowDirection="LeftToRight">
<TextBlock Text="Truck" />
<CheckBox Content="{Binding Path=Name}" />
<CheckBox Content="{Binding Path=MaxLoad}" />
</StackPanel>
</DataTemplate> <!--Sedan Template-->
<DataTemplate x:Key="BindingSample003.Models.Sedan">
<StackPanel Background="LightPink" Margin="12,6" FlowDirection="RightToLeft">
<TextBlock Text="Sedan" />
<TextBlock Text="{Binding Path=Name}" />
<TextBlock Text="{Binding Path=MaxSpeed}" />
</StackPanel>
</DataTemplate> </converters:TypeTemplateConverter.Resources>
</converters:TypeTemplateConverter> </phone:PhoneApplicationPage.Resources>
完成上列的设计与定义之后,透过Binding机制、结合自定义的TypeTemplateConverter,WP8应用程序在Binding时,就可以依照数据对象的DataType选择DataTemplate,并且使用这个DataTemplate的定义来呈现数据对象。例如下列的范例,Truck类别、Sedan类别在经过Binding之后,于画面上Truck类别会有一种呈现外观、而Sedan类别会有另外一种呈现外观。
执行结果

程序代码(.CS)
namespace BindingSample003
{
public partial class MainPage : PhoneApplicationPage
{
// Constructors
public MainPage()
{
// Initialize
this.InitializeComponent(); // Data
var carList = new List<Car>();
carList.Add(new Truck() { Name = "T001", MaxLoad = 100 });
carList.Add(new Sedan() { Name = "S002", MaxSpeed = 200 });
carList.Add(new Truck() { Name = "T003", MaxLoad = 300 });
carList.Add(new Truck() { Name = "T004", MaxLoad = 400 });
carList.Add(new Sedan() { Name = "S005", MaxSpeed = 500 }); // Binding
this.ListBox001.ItemsSource = carList;
}
}
}
程序代码(.XAML)
<!--Resources-->
<phone:PhoneApplicationPage.Resources> <!--Converter-->
<converters:TypeTemplateConverter x:Key="TypeTemplateConverter" >
<converters:TypeTemplateConverter.Resources> <!--Truck Template-->
<DataTemplate x:Key="BindingSample003.Models.Truck">
<StackPanel Background="LightBlue" Margin="12,6" FlowDirection="LeftToRight">
<TextBlock Text="Truck" />
<CheckBox Content="{Binding Path=Name}" />
<CheckBox Content="{Binding Path=MaxLoad}" />
</StackPanel>
</DataTemplate> <!--Sedan Template-->
<DataTemplate x:Key="BindingSample003.Models.Sedan">
<StackPanel Background="LightPink" Margin="12,6" FlowDirection="RightToLeft">
<TextBlock Text="Sedan" />
<TextBlock Text="{Binding Path=Name}" />
<TextBlock Text="{Binding Path=MaxSpeed}" />
</StackPanel>
</DataTemplate> </converters:TypeTemplateConverter.Resources>
</converters:TypeTemplateConverter> </phone:PhoneApplicationPage.Resources> <!--LayoutRoot-->
<ListBox x:Name="ListBox001"> <!--ItemTemplate-->
<ListBox.ItemTemplate>
<DataTemplate>
<ContentControl Content="{Binding}" ContentTemplate="{Binding Converter={StaticResource TypeTemplateConverter}}" HorizontalContentAlignment="Stretch" />
</DataTemplate>
</ListBox.ItemTemplate> <!--Style-->
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</ListBox.ItemContainerStyle> </ListBox>
[WP8] Binding时,依照DataType选择DataTemplate的更多相关文章
- [WP8] Binding时,依照DataType来选择DataTemplate
原文 [WP8] Binding时,依照DataType来选择DataTemplate 范例下载 范例程序代码:点此下载 问题情景 在开发WPF.WP8...这类应用程序的时候,透过Binding机制 ...
- 背水一战 Windows 10 (76) - 控件(控件基类): Control - 基础知识, 焦点相关, 运行时获取 ControlTemplate 和 DataTemplate 中的元素
[源码下载] 背水一战 Windows 10 (76) - 控件(控件基类): Control - 基础知识, 焦点相关, 运行时获取 ControlTemplate 和 DataTemplate 中 ...
- 当没有用 EXISTS 引入子查询时,在选择列表中只能指定一个表达式。
当没有用 EXISTS 引入子查询时,在选择列表中只能指定一个表达式.比如 select * from T_Employee where FNumber not in ( select top 5* ...
- Linux系统安装时分区的选择(推荐)
Linux系统安装时分区的选择(推荐) 出处:http://www.cnblogs.com/gylei/archive/2011/12/04/2275987.html 前言: 以前初识Linux时, ...
- SQL2005:SQL Server 2005还原数据库时出现“不能选择文件或文件组XXX_log用于此操作的解决办法
SQL2005 还原数据库失败,提示如下: SQL Server 2005还原数据库时出现“不能选择文件或文件组XXX_log用于此操作的解决办法 出现错误时操作步骤为:右击数据库--->任务- ...
- (转)Linux系统安装时分区的选择
场景:对于Linux系统的分区总是迷迷茫茫的,还是实践少,基础不牢. 以前初识Linux时,对Linux系统安装时分区的选择,一点都不了解,导致几次没法进行下一步安装,因此就静下心来,专门拿出时间研究 ...
- 构建现代Web应用时究竟是选择传统web应用还是SPA
在大前端盛行的今天,似乎前后端分离的开发模式才是大势所趋,而SPA的概念更是应运而生.现在随便构建一个web应用程序如果你不是使用SPA的话,就会感觉有点low,但是真的是这样吗?今天这篇文章我们就来 ...
- 解决radio、select表单返回时,再次选择失效
应用场景:我们在选择好radio跟select之后提交表单,返回历史记录时,再次选择,提交表单,发现提交的是上次表单选择的 解决办法:我们可以一进页面就给radio跟select的选项重置掉,因为,返 ...
- MyBatis 内置日志工厂基于运行时自省机制选择合适的日志工具
mybatis – MyBatis 3 | 日志 http://www.mybatis.org/mybatis-3/zh/logging.html MyBatis 内置日志工厂基于运行时自省机制选择合 ...
随机推荐
- glow
原则是: 先把原场景渲染到fbo,然后渲染发光的物体 然后叠加,但是问题来了,发光物体是另外一个fbo里渲染的,他没和原场景进行深度测试,导致全部绘制了,叠到一起的时候原先不该显示的部分显示 然后我立 ...
- wndows系统命令总结
window8系统下 打开运行窗口----------鼠标放到任务栏的windows图标下,右击,弹出菜单中如上图或者 打开运行窗口---------按“WIN+R”键, cmd-------打开命令 ...
- Codeforces Beta Round #13 C. Sequence (DP)
题目大意 给一个数列,长度不超过 5000,每次可以将其中的一个数加 1 或者减 1,问,最少需要多少次操作,才能使得这个数列单调不降 数列中每个数为 -109-109 中的一个数 做法分析 先这样考 ...
- JDK的下载、安装及环境变量的配置
官网下载JDK: www.oracle.com 或者 www.java.sun.com 安装JDK: 双击运行下载的 jdk-8u25-windows-i586.exe即可. 假设安装目录为:D: ...
- iOS开发之企业发布无线安装APP
前提是注册成为企业开发者(¥299),申请到证书并安装到本地,可以正常使用Xcode在IOS移动设备上进行Debug. 首先build看是否报错.如无错 执行下一: 执行Product—Archive ...
- TL(简单)
TL time limit per test 2 seconds memory limit per test 256 megabytes input standard input output sta ...
- 爬虫技术 -- 基础学习(五)解决页面编码识别(附c#代码)
实现从Web网页提取文本之前,首先要识别网页的编码,有时候还需要进一步识别网页所使用的语言.因为同一种编码可能对应多种语言,例如UTF-8编码可能对应英文或中文等语言. 识别编码整体流程如下: (1) ...
- 使用Html5+C#+微信 开发移动端游戏详细教程 总目录
(一).序(关于作者创业失败的感想) (二).准备工作&开发环境 (三).使用html5引擎搭建游戏框架 (四).游戏中层的概念与设计 (五).游戏图像的加载与操作 (六).游戏界面布局与性能 ...
- BackgroundCheck – 根据图片亮度智能切换元素样式
BackgroundCheck 是一个轻量的 JavaScript 库,能够根据元素后面的图片的亮度自动切换元素样式.例如在图片幻灯片功能中,根据图片亮度调整导航箭头的颜色,这样让图片和导航的颜色形成 ...
- [Python]同是新手的我,分享一些经验
本来想分享一些知识,但是发现,写着写着,感觉分享一些经验,或许会少让大家走一些弯路,索性就把标题一改. 我不是教给大家些什么,我没有资格,我也是摸着石头过河,我只是本着分享的精神,在这里分享自己的东西 ...