在这片文章中我将解释如何在Silverlight for Windows Phone7中创建一个DataTemplateSelector抽象类以及CustomDataTemplateSelector。DataTemplateSelector可以基于数据对象和数据绑定提供一种方式去选择DataTemplate。特殊情况下,当你对于同一种对象有多个DataTemplate并且你想要按照自己的逻辑去选择DataTemplate应用到各个数据对象的属性的时候需要一些DataTemplateSelector。
总之,DataTemplateSelector使你对于一些特殊项,可以写一些逻辑选择使用哪种DataTemplate。如果有必要,你甚至可以创建一个新的数据模板。
注意:DataTemplateSelector在WPF是一个众所周知的类,但是在Silverlight中不支持。
下面是我在开发者论坛中看到的一个很流行的问题:“我有一列不同类型的元素,我想针对不同的列表元素基于它的类型显示不同的数据模板。”
这个问题的答案就是使用DataTemplateSelector。因此在这篇文章中我会首先解释如何实现DataTemplateSelector抽象类并且证明如何实现你自己的CustomDataTemplateSelector。最后的结果会显示在右边的图中。
实现DataTemplateSelector抽象类
有许多不同的方式创建一个动态的DataTemplateSelector。你可以从WPF的实现中获取一些代码或者尝试用ValueConverter等等。在这篇文章中我将展示利用ContentControl如何创建一个DataTemplateSelector(我将用ContentControl作为基类)。
我首先将要创建一个包含SelectTemplate虚方法的抽象类,此方法返回一个基于Prority属性值的恰当的模板(当在任何为DataTemplateSelector的分部类中重载时)。我将同时重载来自基类的OnContentChanged方法。源代码如下:
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
为了创建CustomDataTemplateSelector,首先创建一个冲DataTemplateSelector类继承的类,并且重载SelectorTemplate方法。一旦你的类定义好之后,你就可以把这个类的实例指定给你的界面元素的template selector property。
我将创建FoodTemplateSelector类,它包括三个不同DataTemplates:Healthy,UnHealthy以及NotDetermined。在SelectorTemplate方法中我将添加一些条件语句来选择合适的DataTemplate。我将基于Data的Type属性值选择正确的模板。
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); } }
以下是Data类:
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;
}
|
然后我将创建三个不同的DataTemplate并且将他们只是为ListBox的ItemTemplate。注意每一个Template是独立的,并且与其它没有联系。这意味着你可以在每个Template中自由添加你想要的任何元素。因此你可以用三种不同的方式展示一个数据源。
最后的结果如左图所示。
下面是每个模板的样式:
以下是源代码:
<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的每一项根据不同的Type属性值使用不同的template。
以下是实现DataTemplateSelector的其他途径链接:
- Using a ValueConverter as a DataTemplateSelector in Silverlight
- DataTemplate Selector with Silverlight
这就是所有关于如何实现DataTemplateSelector抽象类的方法,并且在Silverlight for windows phone 7中如何使用它。你可以在这里找到源代码:WP7SampleProject10.zip
希望这篇文章对你有帮助。