有没有可能遇到这样子的需求,在ListBox里希望列表内加入不同种类的数据,显示的时候又能根据这些数据的类型使用不同的显示方式(在WPF中用DataTemplate来实现,这个大家可能耳熟能详了)。
答案显然是肯定的,有这种需求存在。微软童鞋在WPF框架内考虑到大家的这种交互需求了。解决方案就是使用CompositeCollection。
咋用呢? 举个栗子吧。
在c#源文件中创建ChineseGod类和ChinesesGods类,如下所示:
public class ChineseGod { public string Name { get; set; } public ChineseGod(string n) { Name = n; } } public class ChineseGods : ObservableCollection<ChineseGod> { public ChineseGods() { Add(new ChineseGod("盘古")); Add(new ChineseGod("伏羲")); Add(new ChineseGod("女娲")); } }
c#源代码就如上所示,很简单。接下来是XMAL文件:
<Window.Resources> <c:ChineseGods x:Key="ChineseGodsData"/> <XmlDataProvider x:Key="FriendsData" XPath="Friends/Person"> <x:XData> <Friends xmlns=""> <Person Name="Jason" Parent="c"/> <Person Name="Hercules" Parent="d"/> <Person Name="Bellerophon" Parent="e"/> <Person Name="Theseus" Parent="f"/> <Person Name="Odysseus" Parent="g"/> <Person Name="Perseus" Parent="h"/> </Friends> </x:XData> </XmlDataProvider> <DataTemplate DataType="{x:Type c:ChineseGod}"> <TextBlock Text="{Binding Path=Name}" Foreground="Gold"/> </DataTemplate> <DataTemplate DataType="Person"> <StackPanel Orientation="Horizontal" Margin="5"> <TextBlock Text="{Binding XPath=@Name}" Foreground="Cyan" Width="60"/> <Button Content="{Binding XPath=@Parent}" Width="100"></Button> </StackPanel> </DataTemplate> </Window.Resources> <StackPanel> <TextBlock FontSize="18" FontWeight="Bold" Margin="10" HorizontalAlignment="Center">Composite Collections Sample</TextBlock> <ListBox Name="myListBox" Height="300" Width="200" Background="White"> <ListBox.ItemsSource> <CompositeCollection> <CollectionContainer Collection="{Binding Source={StaticResource ChineseGodsData}}" /> <CollectionContainer Collection="{Binding Source={StaticResource FriendsData}}" /> <ListBoxItem Foreground="Red">Other Listbox Item 1</ListBoxItem> <ListBoxItem Foreground="Red">Other Listbox Item 2</ListBoxItem> </CompositeCollection> </ListBox.ItemsSource> </ListBox> </StackPanel>
如上图所示,我们在ListBox.ItemsSource里头不是直接给ItemsSource赋一个集合,而是通过CompositeCollection将不同类型的集合组合在一起,就像CompositeCollection这个单词名称一样,它是一个组合,将不通的东西都组装在一起了。像这个例子,组合了三种:
第一种
<CollectionContainer Collection="{Binding Source={StaticResource ChineseGodsData}}" />
这种方式,将ListBox绑定到了ChineseGods集合。它的显示方式由下面这个模板定义:
<DataTemplate DataType="{x:Type c:ChineseGod}"> <TextBlock Text="{Binding Path=Name}" Foreground="Gold"/> </DataTemplate>
第二种
<CollectionContainer Collection="{Binding Source={StaticResource FriendsData}}" />
这种方式,将ListBox绑定到了Friends集合,这个集合是用XmlDataProvider方式提供。未来有时间再讲XmlDataProvider这个东东。它的显示方式有下面的这个模板定义:
<DataTemplate DataType="Person"> <StackPanel Orientation="Horizontal" Margin="5"> <TextBlock Text="{Binding XPath=@Name}" Foreground="Cyan" Width="60"/> <Button Content="{Binding XPath=@Parent}" Width="100"></Button> </StackPanel> </DataTemplate>
第三种
<ListBoxItem Foreground="Red">Other Listbox Item 2</ListBoxItem>
至此,大家估计可以想象的出整个显示的结果。嗯,就是如下所示:
这个图就很有说服力了,确实ListBox可以包容万象,可以包含不同种类的数据!
本例子期初来源于微软,本人对这个例子做了一些改动,由于微软原先的例子显示的全是string字符串,组合起来感觉不出类型的差异,结果还是不太容易让人理解CompositeCollection的含义。