我们在将一个数据集合绑定到列表控件时,有时候想根据不同的数据类型,显示为不同的效果。
例如将一个文件夹集合绑定到ListBox时,系统文件夹和普通文件夹分别显示为不同的效果,就可以使用模板选择器功能。
WPF提供了一个模板选择器类型DataTemplateSelector,它可以根据数据对象和数据绑定元素来选择 DataTemplate。
使用方法
创建一个类,继承自DataTemplateSelector,并重写SelectTemplate方法。
类似下面这样
1 using System.Windows; 2 using System.Windows.Controls; 3 4 namespace SDKSample 5 { 6 public class TaskListDataTemplateSelector : DataTemplateSelector 7 { 8 public override DataTemplate 9 SelectTemplate(object item, DependencyObject container) 10 { 11 FrameworkElement element = container as FrameworkElement; 12 13 if (element != null && item != null && item is Task) 14 { 15 Task taskitem = item as Task; 16 17 if (taskitem.Priority == 1) 18 return 19 element.FindResource("importantTaskTemplate") as DataTemplate; 20 else 21 return 22 element.FindResource("myTaskTemplate") as DataTemplate; 23 } 24 25 return null; 26 } 27 } 28 }
下面我们使用ListBox和TreeView进行演示
ListBox的使用示例
我们先定义如下的数据模型
1 public class FileData 2 { 3 public string FileName { get; set; } 4 } 5 6 public class FileData1 : FileData 7 { 8 public string FileData1Property { get; set; } 9 } 10 11 public class FileData2:FileData 12 { 13 public string FileData2Property { get; set; } 14 }
然后定义一个资源字典,分别在里面定义两种数据的数据模板
1 <DataTemplate x:Key="FileData1Datatemplate"> 2 <Grid> 3 <Grid.ColumnDefinitions> 4 <ColumnDefinition/> 5 <ColumnDefinition/> 6 </Grid.ColumnDefinitions> 7 <Label Content="{Binding FileName}" FontSize="20" Foreground="Green"></Label> 8 <Label Content="{Binding FileData1Property}" Grid.Column="1" VerticalAlignment="Center"></Label> 9 </Grid> 10 </DataTemplate> 11 12 <DataTemplate x:Key="FileData2Datatemplate"> 13 <Grid> 14 <Grid.ColumnDefinitions> 15 <ColumnDefinition/> 16 <ColumnDefinition/> 17 </Grid.ColumnDefinitions> 18 <Label Content="{Binding FileName}" FontSize="16" Foreground="Red"></Label> 19 <Label Content="{Binding FileData2Property}" Grid.Column="1" VerticalAlignment="Center"></Label> 20 </Grid> 21 </DataTemplate>
添加测试数据
1 List<FileData> fileDatas = new List<FileData>(); 2 FileData1 fileData1 = new FileData1(); 3 fileData1.FileName = "1.jpg"; 4 fileData1.FileData1Property = "1.jpg property"; 5 FileData2 fileData2 = new FileData2(); 6 fileData2.FileName = "2.jpg"; 7 fileData2.FileData2Property = "2.jpg property"; 8 fileDatas.Add(fileData1); 9 fileDatas.Add(fileData2); 10 this.listbox.ItemsSource = fileDatas;
然后再为ListBox设置DataTemplateSelector
1 this.listbox.ItemTemplateSelector = new ItemDataTemplateSelector();
运行效果如下:
TreeView的使用示例
这里我们定义一个磁盘和文件夹的数据类型,一个磁盘对象可以包含多个文件夹
1 public class Disk 2 { 3 public string DiskName { get; set; } 4 5 public List<Folder> Folders { get; set; } = new List<Folder>(); 6 } 7 8 public class Folder 9 { 10 public string FullPath { get; set; } 11 12 public long Size { get; set; } 13 }
使用使用HierarchicalDataTemplate为TreeView设置层级的数据模板
针对Disk的HierarchicalDataTemplate
1 <HierarchicalDataTemplate x:Key="DiskDatatemplate" ItemsSource="{Binding Folders}" DataType="{x:Type local:Disk}"> 2 <Grid> 3 <Grid.ColumnDefinitions> 4 <ColumnDefinition Width="25"/> 5 <ColumnDefinition/> 6 </Grid.ColumnDefinitions> 7 8 <Image Source="disk.png" Height="25"></Image> 9 <Label Content="{Binding DiskName}" Grid.Column="1"></Label> 10 </Grid> 11 </HierarchicalDataTemplate>
针对Folder的HierarchicalDataTemplate
1 <HierarchicalDataTemplate x:Key="FolderDatatemplate" DataType="{x:Type local:Folder}"> 2 <Grid> 3 <Grid.ColumnDefinitions> 4 <ColumnDefinition Width="25"/> 5 <ColumnDefinition Width="auto"/> 6 <ColumnDefinition/> 7 </Grid.ColumnDefinitions> 8 9 <Image Source="folder.png" Height="25"></Image> 10 <Label Content="{Binding FullPath}" Grid.Column="1"></Label> 11 <Label Content="{Binding Size}" Grid.Column="2"></Label> 12 </Grid> 13 </HierarchicalDataTemplate>
然后我们创建一个DataTemplateSelector,根据不同的数据类型返回不同的HierarchicalDataTemplate
这里仅做演示,实际使用时推荐使用switch并增加错误检测。
1 public class NodeDataTemplateSelector : DataTemplateSelector 2 { 3 public override DataTemplate SelectTemplate(object item, DependencyObject container) 4 { 5 if (item is Disk) 6 return Application.Current.FindResource("DiskDatatemplate") as DataTemplate; 7 else 8 return Application.Current.FindResource("FolderDatatemplate") as DataTemplate; 9 } 10 }
添加测试数据
1 Disk disk = new Disk(); 2 disk.DiskName = "D:\\"; 3 4 Folder folder = new Folder(); 5 folder.FullPath = "D:\\Software"; 6 folder.Size = 1024; 7 disk.Folders.Add(folder); 8 9 Disk disk2 = new Disk(); 10 disk2.DiskName = "E:\\"; 11 12 Folder folder2 = new Folder(); 13 folder2.FullPath = "E:\\Documents"; 14 folder2.Size = 2048; 15 disk2.Folders.Add(folder2); 16 17 List<Disk> disks = new List<Disk>(); 18 disks.Add(disk); 19 disks.Add(disk2); 20 21 this.treeview.ItemsSource = disks;
为TreeView设置DataTemplateSelector
1 this.treeview.ItemTemplateSelector = new NodeDataTemplateSelector();
运行效果
示例代码
github
参考资料:
DataTemplateSelector 类 (System.Windows.Controls) | Microsoft Learn