2.2.5 ItemTemplate、ContentTemplate和DataTemplate

在理解ItemTemplate、ContentTemplate和DataTemplate的关系的之前,我们先来看看ContentControl类和ItemsControl类。ContentControl类是内容控件的基类,如Button, CheckBox,最明显的特征就是这个控件有Content属性,有Content属性的系统控件都是ContentControl的子类。ItemsControl类是列表内容控件的基类,如ListBox,它和ContentControl类是类似的,只不过ContentControl类是单项的内容,ItemsControl是多项的内容。

那么所有继承自ContentControl的内容控件的ContentTemplate属性和所有继承自ItemsControl的列表控件的ItemTemplate属性,都是DataTemplate类型的,意思就是我们可以通过DataTemplate来定义ContentControl和ItemsControl的控件的UI效果和数据的显示。

2.2.6 数据模板的使用

DataTemplate是一种可视化的数据模板,它强大的作用在于可以把数据通过绑定的方式展现到控件上。在上面的例子中,我们介绍了用DataTemplate去实现了UI控件的内容的显示,那么其实DataTemplate最主要的作用并不是去取代ControlTemplate的样式定义,而是通过数据绑定把数据的控件的数据源的信息展现到控件上。

下面我们还是通过一个Button的控件来看一下DataTemplate的数据绑定是如何发挥作用的。

    代码清单2-5数据模板(源代码:第2章\Examples_2_5)

(1)首先定义一个Person类表示是数据实体的类型,代码如下:

    public class Person
{
public string LastName { get; set; }
public string FirstName { get; set; }
}

(2)设计一个DataTemplate,并把这个DataTemplate作为一个资源来使用,这是和Style资源是一样的道理,DataTemplate也可以作为公共的资源给多个控件去使用。那么这个模板的内容是使用StackPanel控件把Person对象的信息水平排列起来。

    < Page.Resources>
<DataTemplate x:Key="PersonNameDataTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding LastName}"/>
<TextBlock Text=", "/>
<TextBlock Text="{Binding FirstName}"/>
</StackPanel>
</DataTemplate>
</ Page.Resources>

(3)创建一个Button控件,把ContentTemplate属性和模板资源关联起来。

     <Button  x:Name="singlePersonButton"  ContentTemplate="{StaticResource PersonNameDataTemplate}"/>

(4)创建一个Person对象并且赋值给Button控件的Content属性。

singlePersonButton.Content = new Person { FirstName = "lee", LastName = "Terry" };

最后我们可以看到按钮的运行效果如图2.14所示,DataTemplate可以把数据对象绑定起来来实现更加灵活的通用的强大的UI数据显示效果。

图2.14 数据模板绑定的按钮

那么刚才的示例是DataTemplate在ContentControl类型的控件上的应用,那么下面我们再来看看DataTemplate在ItemsControl类型的控件上的实现,ContentControl和ItemsControl也是可以直接作为控件去使用的,如果我们并不需要Button或者ListBox这些控件的一些高级功能,就可以直接使用ContentControl或者ItemsControl控件。

(1)定义一个ItemsControl控件,把ItemTemplate属性和模板资源关联起来。

<ItemsControl     x:Name="itemsControl" ItemTemplate="{StaticResource     PersonNameDataTemplate}" />

(2)创建一个Person对象的集合并且赋值给ItemsControl控件的ItemsSource属性。

Persons.Add(new Person { FirstName = "lee2", LastName =     "Terry2" });

Persons.Add(new Person { FirstName = "lee3", LastName =     "Terry3" });

Persons.Add(new Person { FirstName = "lee4", LastName =     "Terry4" });

Persons.Add(new Person { FirstName = "lee5", LastName =     "Terry5" });

itemsControl.ItemsSource = Persons;

这时候可以看到运行效果如图2.15所示,ItemsControl可以把数据集合通过列表的形式展现出来,但是你会发现直接用ItemsControl实现的列表的功能非常有限,并且也不能滚动,接下来再结合一下ContentTemplate来进行完善这个列表的控件。

图2.15 数据模板绑定的列表

(3)定义一个ItemsControl的样式,其实就是自定义一个ControlTemplate的模板作为ItemsControl控件的模板来使用,那么这个模板就是一个内容的展现形式的模板。我们在ControlTemplate模板上定义了一个ScrollViewer控件然后里面再使用了一个StackPanel控件,最里面的是ItemsPresenter控件。列表的DataTemplate的显示内容就是直接投影在ItemsPresenter控件上面的。我们对ScrollViewer控件和StackPanel控件都设置了不同的边框颜色,这样在运行的时候就可以很明显地看出来控件之间的关系是怎样的。

<Style x:Name="ItemsControlStyle"     TargetType="ItemsControl">

            <Setter Property="Template">

            <Setter.Value>

                <ControlTemplate     TargetType="ItemsControl">

                    <ScrollViewer     BorderBrush="Red" BorderThickness="6">

                        <StackPanel     Orientation="Horizontal" Background="Blue">

                            <Border     BorderBrush="Yellow" BorderThickness="3">

                            <ItemsPresenter     />

                            </Border>

                        </StackPanel>

                    </ScrollViewer>

                </ControlTemplate>

            </Setter.Value>

            </Setter>

        </Style>
   

(4)在ItemsControl上添加Style属性为上面定义的样式。

<ItemsControl x:Name="itemsControl"     ItemTemplate="{StaticResource PersonNameDataTemplate}"     Style="{StaticResource ItemsControlStyle}"/>

 

程序的运行效果如图2.16所示。

图2.16 列表控件的各个模块

2.2.7 读取和更换数据模板

对于系统的样式,我们可以通过在C#代码里面读取出来然后再修改,实现动态更换主题的目的。那么技术总是相通的,对于控件的DataTemplate,我们一样也可以通过C#代码去读取出来,然后动态地更换,实现更加丰富和灵活化的样式展示方案。在C#代码里面读取和更换数据模板也是通过对ContentTemplate属性进行读取和赋值就可以了。

这种读取和更换数据模板在列表的控件中会比较常见,比如我要实现一个这样一个功能,通过一个列表展现出一批数据,用户打击某一条数据的时候,这条数据的样式要发生改变,表示选取了这条数据,然后用户可以取消这条数据的选择也可以继续选择多条数据。那么这样的功能在数据多选的情况下是非常普遍的功能来的。下面我们来实现这样的一个功能。

代码清单2-6动态更换样式(源代码:第2章\Examples_2_6)

(1)定义3个DataTemplate资源,一个是非选中状态,一个是选中状态的,还有一个是默认的状态,其实默认的状态和非选中状态是一样的,但是因为默认的状态的数据项样式不能在C#里面再次调用。在两个模板中都添加了Tap事件,用户捕获用户的点击事件。数据源集合与上一个例子一样。

    < Page.Resources>
<!--选中数据项的样式-->
<DataTemplate x:Key="dataTemplateSelectKey" x:Name="dataTemplateSelectName">
<Grid Tapped="StackPanel_Tap_1" Background="Red">
<TextBlock Text="{Binding LastName}" FontSize="50" />
</Grid>
</DataTemplate>
<!--默认数据项的样式,注意默认的数据项样式不能在C#中再次调用-->
<DataTemplate x:Key="dataTemplateDefaultKey" x:Name=" dataTemplateDefaultName">
<StackPanel Orientation="Horizontal" Tapped ="StackPanel_Tap_1">
<TextBlock Text="{Binding LastName}"/>
<TextBlock Text=", "/>
<TextBlock Text="{Binding FirstName}"/>
</StackPanel>
</DataTemplate>
<!--非选中数据项的样式-->
<DataTemplate x:Key="dataTemplateNoSelectKey" x:Name="dataTemplateNoSelectName">
<StackPanel Orientation="Horizontal" Tapped ="StackPanel_Tap_1">
<TextBlock Text="{Binding LastName}"/>
<TextBlock Text=", "/>
<TextBlock Text="{Binding FirstName}"/>
</StackPanel>
</DataTemplate>
</ Page.Resources>
……省略若干代码
//创建ItemsControl控件来绑定列表的数据
<ItemsControl x:Name="listbox" ItemTemplate="{StaticResource dataTemplateDefaultKey }"/>

(2)处理点击事件,判断当前控件的模板和重新赋值模板。可以通过Name属性访问XAML中定义的DataTemplate。

    private void StackPanel_Tap_1(object sender, TappedRoutedEventArgs e)
{
// 获取ItemsControl对象的ItemContainerGenerator属性
// 通过点击的控件的DataContext判断所绑定的数据对象
// 然后从ItemContainerGenerator里面获取到当前的ContentPresenter对象
ContentPresenter myContentPresenter = (ContentPresenter)(listbox.ItemContainerGenerator.ContainerFromItem((sender as Panel).DataContext));
// 判断数据模板是选中状态的还是非选中状态的,然后进行赋值
if (myContentPresenter.ContentTemplate.Equals(dataTemplateSelectName))
{
//赋值非选中状态的模板
myContentPresenter.ContentTemplate = dataTemplateNoSelectName;
}
else
{
//赋值选中状态的模板
myContentPresenter.ContentTemplate = dataTemplateSelectName;
}
}

运行的效果如图2.17所示,当我们点击一下数据项的时候,字体会变大,背景会变成红色,在点击一次就会变成原来的样子。

图2.17 动态更换样式

(3)在这里还要注意一点的是,如果使用的时ListBox控件而不是ItemsControl控件的时候,在获取ContentPresenter对象的时候需要通过可视化树去查找。代码的实现如下所示:

    private void StackPanel_Tap_1(object sender, TappedRoutedEventArgs e)
{
//获取到的对象是ListBoxItem
ListBoxItem myListBoxItem = (ListBoxItem)(listbox.ItemContainerGenerator.ContainerFromItem((sender as Panel).DataContext));
// 在ListBoxItem中查找ContentPresenter
ContentPresenter myContentPresenter = FindVisualChild<ContentPresenter>(myListBoxItem);
……//省略若干代码
}
//查找可视化树某个类型的元素
private childItem FindVisualChild<childItem>(DependencyObject obj) where childItem : DependencyObject
{
for (int i = ; i < VisualTreeHelper.GetChildrenCount(obj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(obj, i);
if (child != null && child is childItem)
return (childItem)child;
else
{
childItem childOfChild = FindVisualChild<childItem>(child);
if (childOfChild != null)
return childOfChild;
}
}
return null;
}

本文来源于《深入理解Windows Phone 8.1 UI控件编程》

源代码下载:http://vdisk.weibo.com/s/zt_pyrfNHoezI

欢迎关注我的微博@WP林政

WP8.1技术交流群:372552293

[WP8.1UI控件编程]Windows Phone理解和运用ItemTemplate、ContentTemplate和DataTemplate的更多相关文章

  1. [WP8.1UI控件编程]Windows Phone XAML页面的编译

    1.1.2 XAML页面的编译 Windows Phone的应用程序项目会通过Visual Studio完成XAML页面的编译,在程序运行时会通过直接链接操作加载和解析XAML,将XAML和过程式代码 ...

  2. [WP8.1UI控件编程]Windows Phone大数据量网络图片列表的异步加载和内存优化

    11.2.4 大数据量网络图片列表的异步加载和内存优化 虚拟化技术可以让Windows Phone上的大数据量列表不必担心会一次性加载所有的数据,保证了UI的流程性.对于虚拟化的技术,我们不仅仅只是依 ...

  3. [WP8.1UI控件编程]Windows Phone VirtualizingStackPanel、ItemsStackPanel和ItemsWrapGrid虚拟化排列布局控件

    11.2.2 VirtualizingStackPanel.ItemsStackPanel和ItemsWrapGrid虚拟化排列布局控件 VirtualizingStackPanel.ItemsSta ...

  4. [WP8.1UI控件编程]Windows Phone动画方案的选择

    8.1 动画方案的选择 Windows Phone的动画实现方式有线性插值动画(3种类型).关键祯动画(4种类型)和基于帧动画,甚至还有定时器动画,然后动画所改变的UI元素属性可以是普通的UI元素属性 ...

  5. [WP8.1UI控件编程]Windows Phone自定义布局规则

    3.2 自定义布局规则 上一节介绍了Windows Phone的系统布局面板和布局系统的相关原理,那么系统的布局面板并不一定会满足所有的你想要实现的布局规律,如果有一些特殊的布局规律,系统的布局面板是 ...

  6. [WP8.1UI控件编程]SemanticZoom控件实现分组列表

    11.1.5 SemanticZoom实现分组列表 SemanticZoom控件可以让用户实现一种更加高级的列表,这种列表可以对列表的项目进行分组,同时这个SemanticZoom控件会提供两个具有相 ...

  7. 《深入理解Windows Phone 8.1 UI控件编程》基于最新的Runtime框架

    <深入理解Windows Phone 8.1 UI控件编程>本书基于最新的Windows Phone 8.1 Runtime SDK编写,全面深入地论述了最酷的UI编程技术:实现复杂炫酷的 ...

  8. MFC控件编程之 按钮编辑框.静态文本的使用,以及访问控件的七种方法.

    MFC控件编程之 按钮编辑框.静态文本的使用以及访问控件的七种方法. 一丶按钮.静态文本的通用属性. 他们都有一个属性.就是可以输入标题内容.以及可以自定义控件ID. 创建一个MFC Dlg对话框. ...

  9. MFC控件编程之鼠标跟键盘消息

    MFC控件编程之鼠标跟键盘消息 在MFC中鼠标消息.键盘消息我们很常用.所以说一下. 鼠标消息分为客户区消息.跟非客户区消息. 一丶客户区消息 我们可以处理消息.来进行我们相应的函数即可. MFC添加 ...

随机推荐

  1. TCP 四次握手

    TCP协议中的三次握手和四次挥手(图解) http://blog.csdn.net/whuslei/article/details/6667471/

  2. org.hibernate.HibernateException: A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance:

    详细错误堆栈信息: org.hibernate.HibernateException: A collection with cascade="all-delete-orphan" ...

  3. Implementing Navigation with UINavigationController

    Implementing Navigation with UINavigationController Problem You would like to allow your users to mo ...

  4. Reporting Services 的伸缩性和性能表现规划(转载)

    简介 Microsoft? SQL Server? Reporting Services 是一个将集中管理的报告服务器具有的伸缩性和易管理性与基于 Web 和桌面的报告交付手段集于一身的报告平台.Re ...

  5. office excel 装Visual Studio后报错解决方案

    安装完vs后,vs会向office安装COM加载项,但是在启动Excel时会发生弹出此加载项安装出错的消息,如下图. 名称: 从: file:///D:/Program Files (x86)/Mic ...

  6. barabasilab-networkScience学习笔记5- Barabási-Albert 模型

    第一次接触复杂性科学是在一本叫think complexity的书上,Allen博士很好的讲述了数据结构与复杂性科学,barabasi是一个知名的复杂性网络科学家,barabasilab则是他所主导的 ...

  7. BootCDN和npm

    稳定.快速.免费的开源项目 CDN 服务 BootCDN: jQuery3 <script type="text/javascript" src="http://c ...

  8. 【hibernate】 hibernate的主键策略

    今天使用maven生成一个sping+springMVC+hibernate 的项目,报错如下: 错误提示呢:不能解释这个id的生成策略[uuid.string].就是uuid.string这个hib ...

  9. Practical Java (一)关于reference

    Practice 1, 4, 7, 8 1. 参数传递:by value or by reference 变量型别:reference 和 primitive Java中的变量分为两种:referen ...

  10. mysql数据库备份与还原命令

    还原一个数据库:mysql -h localhost -u root -p123456 www 备份一个数据库:mysqldump -h localhost -u root -p123456 www ...