[WP8] Binding时,依照DataType选择DataTemplate

范例下载

范例程序代码:点此下载

问题情景

在开发WPF、WP8...这类应用程序的时候,透过Binding机制搭配DataTemplate,能让数据类别在经过Binding之后于画面上呈现。例如下列的范例,透过Binding机制搭配DataTemplate,就能在WP8的ListBox控件中,依照DataTemplate的定义,来呈现Car对象集合。

  • 执行结果

  • 程序代码(.CS)

    1. namespace BindingSample001.Models
    2. {
    3. public class Car
    4. {
    5. public string Name { get; set; }
    6. }
    7. }
    8. namespace BindingSample001
    9. {
    10. public partial class MainPage : PhoneApplicationPage
    11. {
    12. // Constructors
    13. public MainPage()
    14. {
    15. // Initialize
    16. this.InitializeComponent();
    17. // Data
    18. var carList = new List<Car>();
    19. carList.Add(new Car() { Name = "C001" });
    20. carList.Add(new Car() { Name = "C002" });
    21. carList.Add(new Car() { Name = "C003" });
    22. carList.Add(new Car() { Name = "C004" });
    23. carList.Add(new Car() { Name = "C005" });
    24. // Binding
    25. this.ListBox001.ItemsSource = carList;
    26. }
    27. }
    28. }
  • 程序代码(.XAML)

    1. <!--Resources-->
    2. <phone:PhoneApplicationPage.Resources>
    3. <!--Car Template-->
    4. <DataTemplate x:Key="CarTemplate">
    5. <StackPanel Background="LightGreen" Margin="12,6" FlowDirection="LeftToRight">
    6. <TextBlock Text="Car" />
    7. <CheckBox Content="{Binding Path=Name}" />
    8. </StackPanel>
    9. </DataTemplate>
    10. </phone:PhoneApplicationPage.Resources>
    11. <!--LayoutRoot-->
    12. <ListBox x:Name="ListBox001">
    13. <!--ItemTemplate-->
    14. <ListBox.ItemTemplate>
    15. <StaticResource ResourceKey="CarTemplate" />
    16. </ListBox.ItemTemplate>
    17. <!--Style-->
    18. <ListBox.ItemContainerStyle>
    19. <Style TargetType="ListBoxItem">
    20. <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
    21. </Style>
    22. </ListBox.ItemContainerStyle>
    23. </ListBox>

而在一些更复杂的开发项目中,画面上不单单只需要呈现一种的数据类别,而是需要呈现数据类别的各种延伸数据类别,并且这些不同种类的延伸数据类别,在经过Binding之后于画面上必须要有不同种类的呈现外观。例如下列的范例,Car类别为基础数据类别,Truck类别、Sedan类别各自为Car类别的延伸类别,这些Truck类别、Sedan类别在经过Binding之后,于画面上Truck类别会有一种呈现外观、而Sedan类别会有另外一种呈现外观。

本篇文章介绍如何在Binding时,依照数据类别的DataType选择对应的DataTemplate,用以在Binding之后,于画面上依照不同数据类别来呈现不同外观,为自己留个纪录也希望能帮助到有需要的开发人员。

  • 类别结构

  • 类别程序代码(.CS)

    1. public class Car
    2. {
    3. public string Name { get; set; }
    4. }
    5. public class Truck : Car
    6. {
    7. public int MaxLoad { get; set; }
    8. }
    9. public class Sedan : Car
    10. {
    11. public int MaxSpeed { get; set; }
    12. }

在WPF中,依照DataType选择DataTemplate

在WPF中,可以定义DataTemplate.DataType这个属性,用来指定DataTemplate所对应的数据类别。当定义这个属性之后,WPF应用程序在Binding时,就可以依照数据对象的DataType选择DataTemplate,并且使用这个DataTemplate的定义来呈现数据对象。例如下列的范例,Truck类别、Sedan类别在经过Binding之后,于画面上Truck类别会有一种呈现外观、而Sedan类别会有另外一种呈现外观。

  • 执行结果

  • 程序代码(.CS)

    1. namespace BindingSample002
    2. {
    3. public partial class MainWindow : Window
    4. {
    5. // Constructors
    6. public MainWindow()
    7. {
    8. // Initialize
    9. this.InitializeComponent();
    10. // Source
    11. var carList = new List<Car>();
    12. carList.Add(new Truck() { Name = "T001", MaxLoad = 100 });
    13. carList.Add(new Sedan() { Name = "S002", MaxSpeed = 200 });
    14. carList.Add(new Truck() { Name = "T003", MaxLoad = 300 });
    15. carList.Add(new Truck() { Name = "T004", MaxLoad = 400 });
    16. carList.Add(new Sedan() { Name = "S005", MaxSpeed = 500 });
    17. // Binding
    18. this.ListBox001.ItemsSource = carList;
    19. }
    20. }
    21. }
  • 程序代码(.XAML)

    1. <!--Resources-->
    2. <Window.Resources>
    3. <!--Truck Template-->
    4. <DataTemplate DataType="{x:Type models:Truck}">
    5. <StackPanel Background="LightBlue" Margin="12,6" FlowDirection="LeftToRight">
    6. <TextBlock Text="Truck" />
    7. <CheckBox Content="{Binding Path=Name}" />
    8. <CheckBox Content="{Binding Path=MaxLoad}" />
    9. </StackPanel>
    10. </DataTemplate>
    11. <!--Sedan Template-->
    12. <DataTemplate DataType="{x:Type models:Sedan}">
    13. <StackPanel Background="LightPink" Margin="12,6" FlowDirection="RightToLeft">
    14. <TextBlock Text="Sedan" />
    15. <TextBlock Text="{Binding Path=Name}" />
    16. <TextBlock Text="{Binding Path=MaxSpeed}" />
    17. </StackPanel>
    18. </DataTemplate>
    19. </Window.Resources>
    20. <!--LayoutRoot-->
    21. <ListBox x:Name="ListBox001">
    22. <!--Style-->
    23. <ListBox.ItemContainerStyle>
    24. <Style TargetType="ListBoxItem">
    25. <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
    26. </Style>
    27. </ListBox.ItemContainerStyle>
    28. </ListBox>

在WP8中,依照DataType选择DataTemplate

因为一些原因,在WP8中目前没有提供DataTemplate.DataType这个属性,用来指定DataTemplate所对应的数据类别,这也让WP8应用程序,没有办法提供在Binding之后,于画面上依照不同数据类别来呈现不同外观的这个功能。但是山不转路转,开发人员还是可以透过Binding机制、结合自定义的IValueConverter,来提供依照DataType选择DataTemplate这个功能。

  • 程序代码(.XAML)

首先在页面中使用下列的XAML宣告来取代原有的DataTemplate,让DataTemplate的选择机制,改为使用Binding以及自定义的TypeTemplateConverter来提供。

  • 程序代码(.XAML)

    1. <!--LayoutRoot-->
    2. <ListBox x:Name="ListBox001">
    3. <!--ItemTemplate-->
    4. <ListBox.ItemTemplate>
    5. <DataTemplate>
    6. <ContentControl Content="{Binding}" ContentTemplate="{Binding Converter={StaticResource TypeTemplateConverter}}" HorizontalContentAlignment="Stretch" />
    7. </DataTemplate>
    8. </ListBox.ItemTemplate>
    9. <!--Style-->
    10. <ListBox.ItemContainerStyle>
    11. <Style TargetType="ListBoxItem">
    12. <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
    13. </Style>
    14. </ListBox.ItemContainerStyle>
    15. </ListBox>

接着就是依照下列的程序代码来建立自定义的TypeTemplateConverter。这个自定义的TypeTemplateConverter实作IValueConverter,用来处理Binding的目标数据对象,并且依照目标数据对象的型别来提供DataTemplate。

这个设计直觉上会认为没有问题,但实际撰写这个Converter的时候会发现,接收目标数据对象、取得目标数据对象型别这些功能实作都没有问题,但是如何取得DataTemplate却是一个问题(范例中[???]部分的程序代码)。在TypeTemplateConverter并没有定义DataTemplate的来源,没有来源就没有办法取得DataTemplate,那当然也就没有办法依照目标数据对象型别来提供DataTemplate。

  • 程序代码(.CS)

    1. public sealed class TypeTemplateConverter : IValueConverter
    2. {
    3. // Methods
    4. public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    5. {
    6. // Require
    7. if (value == null) return null;
    8. // TypeName
    9. string typeName = value.GetType().ToString();
    10. // DataTemplate
    11. DataTemplate dataTemplate = [???];
    12. if (dataTemplate == null) return null;
    13. // Convert
    14. return dataTemplate;
    15. }
    16. public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    17. {
    18. throw new NotImplementedException();
    19. }
    20. }

这时为了提供DataTemplate的来源,开发人员可以为TypeTemplateConverter类别加入System.Windows.FrameworkElement类别的继承,这样就可以使用FrameworkElement的Resources属性做为DataTemplate的来源。在这之后TypeTemplateConverter就可以使用目标数据对象型别作为索引,取得Resources属性之中的DataTemplate,用以提供Binding机制使用。

  • 程序代码(.CS)

    1. namespace BindingSample003.Converters
    2. {
    3. public sealed class TypeTemplateConverter : System.Windows.FrameworkElement, IValueConverter
    4. {
    5. // Methods
    6. public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    7. {
    8. // Require
    9. if (value == null) return null;
    10. // TypeName
    11. string typeName = value.GetType().ToString();
    12. // DataTemplate
    13. var dataTemplate = this.Resources[typeName] as DataTemplate;
    14. if (dataTemplate == null) return null;
    15. // Convert
    16. return dataTemplate;
    17. }
    18. public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    19. {
    20. throw new NotImplementedException();
    21. }
    22. }
    23. }

为TypeTemplateConverter类别加入System.Windows.FrameworkElement类别的继承之后,在XAML定义中就可以使用XAML语法来定义TypeTemplateConverter对象所要提供的DataTemplate。

  • 程序代码(.XAML)

    1. <!--Resources-->
    2. <phone:PhoneApplicationPage.Resources>
    3. <!--Converter-->
    4. <converters:TypeTemplateConverter x:Key="TypeTemplateConverter" >
    5. <converters:TypeTemplateConverter.Resources>
    6. <!--Truck Template-->
    7. <DataTemplate x:Key="BindingSample003.Models.Truck">
    8. <StackPanel Background="LightBlue" Margin="12,6" FlowDirection="LeftToRight">
    9. <TextBlock Text="Truck" />
    10. <CheckBox Content="{Binding Path=Name}" />
    11. <CheckBox Content="{Binding Path=MaxLoad}" />
    12. </StackPanel>
    13. </DataTemplate>
    14. <!--Sedan Template-->
    15. <DataTemplate x:Key="BindingSample003.Models.Sedan">
    16. <StackPanel Background="LightPink" Margin="12,6" FlowDirection="RightToLeft">
    17. <TextBlock Text="Sedan" />
    18. <TextBlock Text="{Binding Path=Name}" />
    19. <TextBlock Text="{Binding Path=MaxSpeed}" />
    20. </StackPanel>
    21. </DataTemplate>
    22. </converters:TypeTemplateConverter.Resources>
    23. </converters:TypeTemplateConverter>
    24. </phone:PhoneApplicationPage.Resources>

完成上列的设计与定义之后,透过Binding机制、结合自定义的TypeTemplateConverter,WP8应用程序在Binding时,就可以依照数据对象的DataType选择DataTemplate,并且使用这个DataTemplate的定义来呈现数据对象。例如下列的范例,Truck类别、Sedan类别在经过Binding之后,于画面上Truck类别会有一种呈现外观、而Sedan类别会有另外一种呈现外观。

  • 执行结果

  • 程序代码(.CS)

    1. namespace BindingSample003
    2. {
    3. public partial class MainPage : PhoneApplicationPage
    4. {
    5. // Constructors
    6. public MainPage()
    7. {
    8. // Initialize
    9. this.InitializeComponent();
    10. // Data
    11. var carList = new List<Car>();
    12. carList.Add(new Truck() { Name = "T001", MaxLoad = 100 });
    13. carList.Add(new Sedan() { Name = "S002", MaxSpeed = 200 });
    14. carList.Add(new Truck() { Name = "T003", MaxLoad = 300 });
    15. carList.Add(new Truck() { Name = "T004", MaxLoad = 400 });
    16. carList.Add(new Sedan() { Name = "S005", MaxSpeed = 500 });
    17. // Binding
    18. this.ListBox001.ItemsSource = carList;
    19. }
    20. }
    21. }
  • 程序代码(.XAML)

    1. <!--Resources-->
    2. <phone:PhoneApplicationPage.Resources>
    3. <!--Converter-->
    4. <converters:TypeTemplateConverter x:Key="TypeTemplateConverter" >
    5. <converters:TypeTemplateConverter.Resources>
    6. <!--Truck Template-->
    7. <DataTemplate x:Key="BindingSample003.Models.Truck">
    8. <StackPanel Background="LightBlue" Margin="12,6" FlowDirection="LeftToRight">
    9. <TextBlock Text="Truck" />
    10. <CheckBox Content="{Binding Path=Name}" />
    11. <CheckBox Content="{Binding Path=MaxLoad}" />
    12. </StackPanel>
    13. </DataTemplate>
    14. <!--Sedan Template-->
    15. <DataTemplate x:Key="BindingSample003.Models.Sedan">
    16. <StackPanel Background="LightPink" Margin="12,6" FlowDirection="RightToLeft">
    17. <TextBlock Text="Sedan" />
    18. <TextBlock Text="{Binding Path=Name}" />
    19. <TextBlock Text="{Binding Path=MaxSpeed}" />
    20. </StackPanel>
    21. </DataTemplate>
    22. </converters:TypeTemplateConverter.Resources>
    23. </converters:TypeTemplateConverter>
    24. </phone:PhoneApplicationPage.Resources>
    25. <!--LayoutRoot-->
    26. <ListBox x:Name="ListBox001">
    27. <!--ItemTemplate-->
    28. <ListBox.ItemTemplate>
    29. <DataTemplate>
    30. <ContentControl Content="{Binding}" ContentTemplate="{Binding Converter={StaticResource TypeTemplateConverter}}" HorizontalContentAlignment="Stretch" />
    31. </DataTemplate>
    32. </ListBox.ItemTemplate>
    33. <!--Style-->
    34. <ListBox.ItemContainerStyle>
    35. <Style TargetType="ListBoxItem">
    36. <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
    37. </Style>
    38. </ListBox.ItemContainerStyle>
    39. </ListBox>

[WP8] Binding时,依照DataType选择DataTemplate的更多相关文章

  1. [WP8] Binding时,依照DataType来选择DataTemplate

    原文 [WP8] Binding时,依照DataType来选择DataTemplate 范例下载 范例程序代码:点此下载 问题情景 在开发WPF.WP8...这类应用程序的时候,透过Binding机制 ...

  2. 背水一战 Windows 10 (76) - 控件(控件基类): Control - 基础知识, 焦点相关, 运行时获取 ControlTemplate 和 DataTemplate 中的元素

    [源码下载] 背水一战 Windows 10 (76) - 控件(控件基类): Control - 基础知识, 焦点相关, 运行时获取 ControlTemplate 和 DataTemplate 中 ...

  3. 当没有用 EXISTS 引入子查询时,在选择列表中只能指定一个表达式。

    当没有用 EXISTS 引入子查询时,在选择列表中只能指定一个表达式.比如 select * from T_Employee where FNumber not in ( select top 5*  ...

  4. Linux系统安装时分区的选择(推荐)

    Linux系统安装时分区的选择(推荐)  出处:http://www.cnblogs.com/gylei/archive/2011/12/04/2275987.html 前言: 以前初识Linux时, ...

  5. SQL2005:SQL Server 2005还原数据库时出现“不能选择文件或文件组XXX_log用于此操作的解决办法

    SQL2005 还原数据库失败,提示如下: SQL Server 2005还原数据库时出现“不能选择文件或文件组XXX_log用于此操作的解决办法 出现错误时操作步骤为:右击数据库--->任务- ...

  6. (转)Linux系统安装时分区的选择

    场景:对于Linux系统的分区总是迷迷茫茫的,还是实践少,基础不牢. 以前初识Linux时,对Linux系统安装时分区的选择,一点都不了解,导致几次没法进行下一步安装,因此就静下心来,专门拿出时间研究 ...

  7. 构建现代Web应用时究竟是选择传统web应用还是SPA

    在大前端盛行的今天,似乎前后端分离的开发模式才是大势所趋,而SPA的概念更是应运而生.现在随便构建一个web应用程序如果你不是使用SPA的话,就会感觉有点low,但是真的是这样吗?今天这篇文章我们就来 ...

  8. 解决radio、select表单返回时,再次选择失效

    应用场景:我们在选择好radio跟select之后提交表单,返回历史记录时,再次选择,提交表单,发现提交的是上次表单选择的 解决办法:我们可以一进页面就给radio跟select的选项重置掉,因为,返 ...

  9. MyBatis 内置日志工厂基于运行时自省机制选择合适的日志工具

    mybatis – MyBatis 3 | 日志 http://www.mybatis.org/mybatis-3/zh/logging.html MyBatis 内置日志工厂基于运行时自省机制选择合 ...

随机推荐

  1. 算法导论第十八章 B树

    一.高级数据结构 本章以后到第21章(并查集)隶属于高级数据结构的内容.前面还留了两章:贪心算法和摊还分析,打算后面再来补充.之前的章节讨论的支持动态数据集上的操作,如查找.插入.删除等都是基于简单的 ...

  2. 图文安装Windows Template Library - WTL Version 9.0

    从http://wtl.sourceforge.net/下载 WTL 9.0,或者点此链接下载:WTL90_4140_Final.zip,然后解压到你的VC目录下面, 我的地址是:C:\Program ...

  3. [转]Handy adb commands for Android

    转自:http://www.growingwiththeweb.com/2014/01/handy-adb-commands-for-android.html View connected devic ...

  4. 【迁移学习】2010-A Survey on Transfer Learning

    资源:http://www.cse.ust.hk/TL/ 简介: 一个例子: 关于照片的情感分析. 源:比如你之前已经搜集了大量N种类型物品的图片进行了大量的人工标记(label),耗费了巨大的人力物 ...

  5. Inkpad中文翻译已合并到官方项目

    今天 Steve Sprang 已合并了#100提交请求,Inkpad即将在AppStore上发布简体中文版了! 20天前因一个偶然原因启动翻译的: 当晚(周六)我想对iPad上的矢量绘图软件进行交互 ...

  6. ARM Linux 3.x的设备树(Device Tree)

    1. ARM Device Tree起源 Linus Torvalds在2011年3月17日的ARM Linux邮件列表宣称“this whole ARM thing is a f*cking pai ...

  7. shell 和awk性能对比

    time for ((i=0;i<10000;i++)) do ((sum+=i)); done real    0m0.086suser    0m0.079ssys    0m0.007s ...

  8. MySQL工具汇总

    本博客已经迁移至:http://cenalulu.github.io/ 本篇博文已经迁移,阅读全文请点击:http://cenalulu.github.io/mysql/mysql-tools-lis ...

  9. Spring Remoting: Burlap--转

    原文地址:http://www.studytrails.com/frameworks/spring/spring-remoting-burlap.jsp Concept Overview In the ...

  10. ShortcutMapper – 热门应用程序的可视化快捷键

    ShortcutMapper 是一个流行应用程序的键盘快捷键映射.该应用程序使用 Ajax 调用来加载键盘和应用程序数据.首先,试图找到一个在线资源,其中列出了每个平台的所有应用程序快捷方式.然后你可 ...