实现Windows Phone7 的DataTemplateSelector和CustomDataTemplateSelector

在这篇文章中,我将要介绍在Windows Phone 7开发环境中怎么去创建一个DataTemplateSelector的虚类和自定义一个CustomDataTemplateSelector。通常DataTemplateSelector提供一种基于数据对象和数据绑定的选择DataTemplate的途径。特别是在对于同类的对象有多个DataTemplate,并且能根据逻辑选择DataTemplate应用到数据对象上。

简单的说,DataTemplateSelector允许我们编写一些逻辑去选择哪个DataTemplate运用到哪个特定的项上。甚至可以创建一个新的Template 。

  

NOTE: DataTemplateSelector 在WPF中是一个很好用的类,不过它现在还没有Silverlight版本

下面是一个在dev forums很热门的一个问题

"I have a list of different types of elements. I would like to display a different data template for different list elements, based on what type it is. "

这个问题的答案是利用DataTemplateSelector。因此在这篇文章里我先要解释怎么去实现一个DataTemplateSelector,然后我会介绍怎么去实现自己的自定义CustomDataTemplateSelector 。最后的效果图会贴在本文中。

 

实现DataTemplateSelector虚类

有很多的方法去建立一个动态的DataTemplateSelector 。你可以从WPF默认实现DataTemplateSelector的代码中去提取代码,利用ValueConverter实现等等。在这篇文章中我会介绍怎么去建立一个继承自ContentControl(这里把ContentControl当做一个基类) 的DataTemplateSelector 。

我们要做的第一件事就是建立一个带有选择合适Template虚方法抽象类。这个虚方法SelectTemplate可以根据优先属性的值(在一个继承自DataTemplateSelector特定的类被重写时)返回一个合适的Template。这里需要重写基类的OnContentChanhed 事件,下面是源码:

public abstract class DataTemplateSelector : ContentControl
{
    public virtual DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        return null;
    }

    protected override void OnContentChanged(object oldContent, object newContent)
    {
        base.OnContentChanged(oldContent, newContent);

        ContentTemplate = SelectTemplate(newContent, this);
    }
}

 

建立一个自定义的CustomDataTemplateSelector

为了建立一个自定义的模板选择器,首先需要建立一个继承自DataTemplateSelector 的类,然后要override它的SelectTemplate方法。一旦你的类定义好之后,你就可以把这个类的实例指定给你的界面element的template selector property。

为了演示,这里我会建立一个FoodTemplateSelector 类,它包含三个不同的DataTemplates:Healthy, UnHealthy and NotDetermined。在SelectTemplate 方法里我会加上一些条件,这些条件可以根据 data context的属性值选择合适的DataTemplate。基本上我们可以通过数据源的属性值选择正确的template。

这个FoodTemplateSelector 的源码如下:

public class FoodTemplateSelector : DataTemplateSelector
{
    public DataTemplate Healthy
    {
        get;
        set;
    }

    public DataTemplate UnHealthy
    {
        get;
        set;
    }

    public DataTemplate NotDetermined
    {
        get;
        set;
    }

    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        Data foodItem = item as Data;
        if (foodItem != null)
        {
            if (foodItem.Type == "Healthy")
            {
                return Healthy;
            }
            else if (foodItem.Type == "NotDetermined")
            {
                return NotDetermined;
            }
            else
            {
                return UnHealthy;
            }
        }

        return base.SelectTemplate(item, container);
    }
}

这里是数据类:

public class Data
{
    public string Name
    {
        get;
        set;
    }

    public string Description
    {
        get;
        set;
    }

    public string IconUri
    {
        get;
        set;
    }

    public string Type
    {
        get;
        set;
    }
}

这里为了表明FoodTemplateSelector的用法,使用了一个数据绑定的ListBox。这里是绑定的源码:

public MainPage()
{
    InitializeComponent();

     List<Data> list = new List<Data>();
     Data item0 = new Data() { Name = "Tomato", IconUri = "Images/Tomato.png", Type = "Healthy" };
     Data item1 = new Data() { Name = "Beer", IconUri = "Images/Beer.png", Type = "NotDetermined" };
     Data item2 = new Data() { Name = "Fries", IconUri = "Images/fries.png", Type = "Unhealthy" };
     Data item3 = new Data() { Name = "Sandwich", IconUri = "Images/Hamburger.png", Type = "Unhealthy" };
     Data item4 = new Data() { Name = "Ice-cream", IconUri = "Images/icecream.png", Type = "Healthy" };
     Data item5 = new Data() { Name = "Pizza", IconUri = "Images/Pizza.png", Type = "Unhealthy" };
     Data item6 = new Data() { Name = "Pepper", IconUri = "Images/Pepper.png", Type = "Healthy" };
     list.Add(item0);
     list.Add(item1);
     list.Add(item2);
     list.Add(item3);
     list.Add(item4);
     list.Add(item5);
     list.Add(item6);

     this.listBox.ItemsSource = list;
                
}

下一步要做的是建立三个DataTemplates 并且把它们分别设定成ListBox的一个ItemTemplate。因为这三个DataTemplate都是独立的相互之间没有联系,这意味着你可以在每个DataTemplate上使用任何的element。因此一个数据源可以三种不同的显示。

左边的是效果图,这是这三个DataTemplates 的模样:                 


                                                    

建立 ListBox的源码如下:

<ListBox x:Name="listBox" HorizontalContentAlignment="Stretch">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <local:FoodTemplateSelector Content="{Binding}">
                <local:FoodTemplateSelector.Healthy>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal" Background="YellowGreen" Width="400" Margin="10">
                            <Image Source="{Binding IconUri}" Stretch="None"/>
                            <TextBlock Text="{Binding Name}" FontSize="40" Foreground="Black" Width="280"/>
                            <TextBlock Text="healty" />
                        </StackPanel>
                    </DataTemplate>
                    </local:FoodTemplateSelector.Healthy>
                <local:FoodTemplateSelector.UnHealthy>
                    <DataTemplate>
                        <Border BorderBrush="Red" BorderThickness="2"  Width="400" Margin="10">
                        <StackPanel Orientation="Horizontal">
                            <Image Source="{Binding IconUri}" Stretch="None"/>
                                <TextBlock Text="{Binding Name}" FontSize="40" Width="280"/>
                            <Image Source="Images/attention.png" Stretch="None" Margin="10,0,0,0"/>
                        </StackPanel>
                        </Border>
                    </DataTemplate>
                </local:FoodTemplateSelector.UnHealthy>
                <local:FoodTemplateSelector.NotDetermined>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal" Background="Gray" Width="400" Margin="10">
                            <Image Source="{Binding IconUri}" Stretch="None"/>
                            <TextBlock Text="{Binding Name}" FontSize="40" Width="280"/>
                            <Image Source="Images/question.png" Stretch="None" Margin="10,0,0,0"/>
                        </StackPanel>
                    </DataTemplate>
                </local:FoodTemplateSelector.NotDetermined>
            </local:FoodTemplateSelector>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

最终的结果:ListBox的每一个item由于不同的Type属性值都有不同的template 。

 

这里贴出有用的链接,提供了实现DataTemplateSelector  的途径:

到这里,关于如何建立建立DataTemplateSelector 虚类和如何在Silverlight for Windows Phone 7中使用它的方法就介绍完了。

附上示例源码包下载:WP7DataTemplateSelector.zip


希望它能对你有用。
原文地址:windowsphonegeekDataTemplateSelector
posted @ 2011-08-20 12:36  huangliangjie  阅读(153)  评论(0编辑  收藏  举报