[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的更多相关文章

  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. Foundation和UIKit框架组织图

    转自:http://fantom.iteye.com/blog/1776558

  2. itextpdf JAVA 输出PDF文档

    使用JAVA生成PDF的时候,还是有些注意事项需要处理的. 第一.中文问题,默认的itext是不支持中文的,想要支持,需要做些处理. 1.直接引用操作系统的中文字体库支持,由于此方案限制性强,又绑定了 ...

  3. Android odex文件反编译

    odex 是经过优化的dex文件,且独立存在于apk文件.odex 多用于系统预制应用或服务.通过将apk中的dex文件进行 odex,可以加载 apk 的启动速度,同时减小空间的占用.请参考ODEX ...

  4. 10个TWaver 网页3D可视化精彩案例

    以下网页3D案例均为TWaver原创出品,推荐使用Chrome, FireFox, Safari等对WebGL支持良好的浏览器运行.案例排名不分先后,如需Demo,可直接申请试用.   1. 化学元素 ...

  5. Sql触发器模板

    触发器是一种特殊类型的存储过程,它不同于之前的我们介绍的存储过程. 触发器主要是通过事件进行触发被自动调用执行的.而存储过程可以通过存储过程的名称被调用. SQL Server 2005中触发器可以分 ...

  6. PLSQL快捷补充代码设置

    菜单Tools-->Preferences...然后依次选择下图红色选项 弹出下图对话框 输入需要快速生成的语句点击保存 点击Save后在slq窗口中输入 设置的语句缩写 列入:第一个sf  然 ...

  7. php和egret的配合

    egret对资源路径和js的应用都是相对路径,而在现在许多流行的框架里,一般都把js和资源放到专门的文件夹下,如public. 修改步骤: 1.修改index.html,改为全路径,如: <sc ...

  8. java中反射机制通过字节码文件对象获取字段和函数的方法

    pclass = Class.forName("get_class_method.Person"); //Field ageField = pclass.getField(&quo ...

  9. sqlserver -- 学习笔记(三)解决php连接sqlserver2005视图时显示“异类查询要求为连接设置 ANSI_NULLS 和 ANSI_WARNINGS 选项”的问题

    --php5.2 --sqlserver2005 php连接sqlserver的视图aa,语句如下: $query = mssql_query("select * from dbo.aa&q ...

  10. Tips10:你可以像写文档一样自由的复制粘贴游戏组件(Game Object Component)

    相对于添加组件后再进行调整和赋值,通过复制和粘贴已有游戏组件能够带来更高的效率.