[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机制搭配Da ...
- (转)类(class)和结构(struct)的区别是什么?它们对性能有影响吗?.NET BCL里有哪些是类(结构),为什么它们不是结构(类)?在自定义类型时,您如何选择是类还是结构?
转自:http://blog.csdn.net/lingxyd_0/article/details/8695747 类(class)和结构(struct)的区别是什么?它们对性能有影响吗?.NET B ...
- 我们在部署 HTTPS 网站时,该如何选择SSL证书?
我们在部署 HTTPS 网站时,该如何选择SSL证书? 首次部署HTTPS网站的同学对选择什么样的SSL证书多多少少都有点迷茫. 这里考虑的因素确实不少:是否支持多域名.泛域名,价格,信息泄露的保额, ...
- 创建pycharm项目时项目解释器的选择
创建pycharm项目时项目解释器的选择 Location下面有一个Project Interpreter: Python3.6,打开之后有两个选项, 如果选择了第一个,项目创建之后,在cmd中pip ...
- 借鉴seisman安装软件时的文件放置选择
对于大型的软件包的安装来说: 当下载成功一个软件的压缩包后: tar -xvf xxxx.tgz ./configure --prefix=/opt/xxxx make sudo make insta ...
- 安装APK时SO库的选择策略
此文已由作者尹彬彬授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 0X0 前言 在Android系统中,当我们安装apk文件的时候,lib目录下的so文件会被解压到app的原 ...
- C++开发时字符编码的选择
最近看了很多有关字符编码的讨论帖子, 自己也做了很多尝试, 针对linux和windows上字符编码的选择做了个简单整理, 在此做个记录 首先是基础编码知识, 下面我列出的4个编码方式或字符集是我们应 ...
- 编译时IOS Device 无法选择的情况
问题描述:当你项目开发环境Xocode版本高于你本地Xocode 编译版本时,在本地运行会出现如下错误: 解决: 重写调整Deloyment Target 的版本 注:还有一种情况会出现如上错误,并 ...
- SideBar 选择城市时右侧边上的 选择bar
需要定义一个SideBar的视图类 在布局文件中引用 同时在布局中设置一个textView默认不可见 当触摸时才显示 在调用的Activity中 sideBar.setOnTouchingL ...
随机推荐
- JSONP跨域的原理解析[转]
转自 http://www.nowamagic.net/librarys/veda/detail/224 JavaScript是一种在Web开发中经常使用的前端动态脚本技术.在JavaScript中, ...
- 为什么国内的网盘公司都在 TB 的级别上竞争,成本会不会太高?(还有好多其它回复)
作者:杜鑫链接:http://www.zhihu.com/question/21591490/answer/18762821来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处 ...
- Firemonkey使用iOS的第三方静态库(Link Binary With Libraries)
最近需要从内存流中直接播放音频,想到了使用第三方音频播放库bass.在windows上可以很方便的使用相应动态库(具体参考万一的博客),但在iOS上却没有相应的使用介绍,准确的说是没有用于Firemo ...
- Linux看门狗脚本 1.4
近期项目的看门狗经历了三个版本号. 第一个版本号: 用ps -ef,假设程序挂了就启动 第二个版本号: 程序因为执行时会出现不再监听7901port,所以不能简单推断机器是不是挂了,而是推断此port ...
- Oracle基础(五):多表查询
一.多表查询 (一)简单多表查询 1.多表查询的机制 1)SQL: SELECT * FROM emp; --14条记录 SELECT * FROM dept;--4条记录 SELECT * FROM ...
- xp每天定时关机命令
at 00:00 /every:M,T,W,Th,F,S,Su shutdown -s -t 120 能够把00:00改成你想要每天定时关机的时间,120是指关机倒计时的秒数,也能够更改 M,T,W, ...
- [转]给Linux系统管理员准备的Nmap命令的29个实用范例+ tsysv 系统服务器管理器
原文链接:http://os.51cto.com/art/201401/428152.htm Nmap即网络映射器对Linux系统/网络管理员来说是一个开源且非常通用的工具.Nmap用于在远程机器上探 ...
- nginx 解决400 bad request 的方法
nginx的400错误比较难查找原因,因为此错误并不是每次都会出现的,另外,出现错误的时候,通常在浏览器和日志里看不到任何有关提示. 经长时间观察和大量试验查明,此乃request header过大所 ...
- 转载python并行运算实例
Python的并发处理能力臭名昭著.先撇开线程以及GIL方面的问题不说,我觉得多线程问题的根源不在技术上而在于理念.大部分关于Pyhon线程和多进程的资料虽然都很不错,但却过于细节.这些资料讲的都是虎 ...
- android-studio 安装gradle
http://services.gradle.org/distributions 下载需要的gradle 放到C:\Users\Administrator\.gradle\wrapper\dists\ ...