原文 [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机制搭配Da ...

  2. (转)类(class)和结构(struct)的区别是什么?它们对性能有影响吗?.NET BCL里有哪些是类(结构),为什么它们不是结构(类)?在自定义类型时,您如何选择是类还是结构?

    转自:http://blog.csdn.net/lingxyd_0/article/details/8695747 类(class)和结构(struct)的区别是什么?它们对性能有影响吗?.NET B ...

  3. 我们在部署 HTTPS 网站时,该如何选择SSL证书?

    我们在部署 HTTPS 网站时,该如何选择SSL证书? 首次部署HTTPS网站的同学对选择什么样的SSL证书多多少少都有点迷茫. 这里考虑的因素确实不少:是否支持多域名.泛域名,价格,信息泄露的保额, ...

  4. 创建pycharm项目时项目解释器的选择

    创建pycharm项目时项目解释器的选择 Location下面有一个Project Interpreter: Python3.6,打开之后有两个选项, 如果选择了第一个,项目创建之后,在cmd中pip ...

  5. 借鉴seisman安装软件时的文件放置选择

    对于大型的软件包的安装来说: 当下载成功一个软件的压缩包后: tar -xvf xxxx.tgz ./configure --prefix=/opt/xxxx make sudo make insta ...

  6. 安装APK时SO库的选择策略

    此文已由作者尹彬彬授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 0X0 前言 在Android系统中,当我们安装apk文件的时候,lib目录下的so文件会被解压到app的原 ...

  7. C++开发时字符编码的选择

    最近看了很多有关字符编码的讨论帖子, 自己也做了很多尝试, 针对linux和windows上字符编码的选择做了个简单整理, 在此做个记录 首先是基础编码知识, 下面我列出的4个编码方式或字符集是我们应 ...

  8. 编译时IOS Device 无法选择的情况

    问题描述:当你项目开发环境Xocode版本高于你本地Xocode 编译版本时,在本地运行会出现如下错误: 解决:  重写调整Deloyment Target 的版本 注:还有一种情况会出现如上错误,并 ...

  9. SideBar 选择城市时右侧边上的 选择bar

    需要定义一个SideBar的视图类  在布局文件中引用   同时在布局中设置一个textView默认不可见 当触摸时才显示   在调用的Activity中 sideBar.setOnTouchingL ...

随机推荐

  1. PigCms 回复消息 "域名授权错误! 您使用的微信平台或源码为盗版"

    本文地址:http://duwei.cnblogs.com/ Pigcms 将自动回复的API 写死了, 这里提供一个可用的API 在 PigCms/Lib/Action/Home/Weixinact ...

  2. Scriptcase在线试用开发环境

    现在,你可以通过浏览器在线试用的方式,体验Scriptcase的高效快速开发方式. 只需要有上网环境就可以使用: 兼容几乎所有的浏览器(IE.Firefox.Chrome.Opera……): 客户端无 ...

  3. 基于visual Studio2013解决算法导论之048红黑树

     题目 红黑树 解决代码及点评 // 红黑树.cpp : 定义控制台应用程序的入口点. // #include <stdio.h> #include <stdlib.h> ...

  4. iframe,window,滚动栏的一些问题

    1.Iframe不显示边框:frameborder=0 2.Iframe不显示横向滚动栏:在iframe所指向的页面增加: <style> html{overflow-x:hidden;} ...

  5. DHCP的工作原理

    什么是dhcp?它是如何实现的? DHCP称为动态主机配置协议.DHCP服务允许工作站连接到网络并且自动获取一个IP地址.配置DHCP服务的服务器可以为每一个网络客户提供一个IP地址.子网掩码.缺省网 ...

  6. java操作Excel处理数字类型的精度损失问题验证

    java操作Excel处理数字类型的精度损失问题验证: 场景: CELL_TYPE_NUMERIC-->CELL_TYPE_STRING--->CELL_TYPE_NUMERIC POI版 ...

  7. (step8.2.6)hdu 1848(Fibonacci again and again——组合博弈)

    题目大意:输入3个整数m,n,p,分别表示3堆石头中的石头个数 解题思路: 1)斐波那契数列的第16个数fib[16] == 1597 2)(sg[m]^sg[n]^sg[p])   .一定要加括号, ...

  8. Offer_1

    #include <iostream> #include <cstring> using namespace std; class CMyString { public: CM ...

  9. 关于caffe-windows中 compute_image_mean.exe出现的问题

    这两天有兴致装了下caffe.感受下这个框架. 可是在这个过程中遇到非常多问题.我把碰到的问题和解决方式写下,便于后人高速上手. compute_image_mean.exe 编译出来后.运行数据变换 ...

  10. WCF技术剖析之十:调用WCF服务的客户端应该如何进行异常处理

    原文:WCF技术剖析之十:调用WCF服务的客户端应该如何进行异常处理 在前面一片文章(服务代理不能得到及时关闭会有什么后果?)中,我们谈到及时关闭服务代理(Service Proxy)在一个高并发环境 ...