一、问题场景
日常为 TreeView
自定义样式过程中,如果涉及到树形多级样式不同时,又该如何去做?例如树形显示文件夹和文件节点。
TreeView
样式如下:
<HierarchicalDataTemplate x:Key="Folder" DataType="{x:Type local:TreeItemViewModel}" ItemsSource="{Binding Children}"> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding Name}"/> <TextBlock Text="/"/> <TextBlock Text="{Binding TreeType}"/> </StackPanel> </HierarchicalDataTemplate> <HierarchicalDataTemplate x:Key="Node" DataType="{x:Type local:TreeItemViewModel}" ItemsSource="{Binding Children}"> <TextBlock Text="{Binding Name}"/> </HierarchicalDataTemplate> <TreeView ItemTemplate="{DynamicResource Folder}" x:Name="treeview" Width="200" DataContext="{StaticResource TreeViewModel}" local:TreeViewAttach.SelectItem="{Binding SeletedItem,Mode=TwoWay}" local:TreeViewAttach.SelectedMonitored="True" ItemsSource="{Binding Path=TreeItems}" VirtualizingPanel.IsVirtualizing="True" VirtualizingPanel.IsVirtualizingWhenGrouping="True"> </TreeView>
TreeViewModel
内容如下:
public class TreeViewModel:Prism.Mvvm.BindableBase { private List<TreeItemViewModel> treeItems; public TreeViewModel() { for (int i = 0; i < 10; i++) { TreeItemViewModel item = new TreeItemViewModel { Name = $"test{i}", }; for (int j = 0; j < 10; j++) { TreeItemViewModel item01 = new TreeItemViewModel { Name = $"孩子-{i}", }; var child = new TreeItemViewModel { Name = $"c{i}-{j}" }; for (int m = 0; m < 10; m++) { var childsub = new TreeItemViewModel { Name = $"{child.Name}-{m}" }; child.Children.Add(childsub); } item.Children.Add(item01); item.Children.Add(child); } TreeItems.Add(item); } } public List<TreeItemViewModel> TreeItems { get { if (treeItems == null) { treeItems = new List<TreeItemViewModel>(); } return treeItems; } set => SetProperty(ref treeItems, value); } }
子项TreeViewItemModel
内容如下:
public class TreeItemViewModel : Prism.Mvvm.BindableBase { private string name; public string Name { get => name; set => SetProperty(ref name, value); } private List<TreeItemViewModel> children; public List<TreeItemViewModel> Children { get { if (children == null) { children = new List<TreeItemViewModel>(); } return children; } set => SetProperty(ref children, value); } public TreeType TreeType { get { if (children != null && children.Count > 0) { return TreeType.Folder; } return TreeType.Node; } } }
运行效果如下:
可以看到,所有的样式都是使用的 Key="Folder"
的样式模板。
二、解决思路
如果希望多个样式都应用到 TreeView
中时,需要考虑是否能够给 HierarchicalDataTemplate
本身添加额外的样式。查看 HierarchicalDataTemplate
内部代码:
public class HierarchicalDataTemplate : DataTemplate { public int AlternationCount{} public BindingGroup ItemBindingGroup{} public Style ItemContainerStyle{} public StyleSelector ItemContainerStyleSelector{} public BindingBase ItemsSource{} public string ItemStringFormat{} public DataTemplate ItemTemplate{} public DataTemplateSelector ItemTemplateSelector{} public HierarchicalDataTemplate(){} public HierarchicalDataTemplate(object dataType){} }
HierarchicalDataTemplate
为 DataTempate
的派生类,同时,也可以将 HierarchicalDataTemplate
视为一个集合控件,能够 ItemTemplate
,也能够添加 ItemTemplateSelector
,那么此时就可以尝试,通过为 HierarchicalDataTemplate
添加数据模板选择器,进行 HierarchicalDataTemplate
内容项的样式选择。
选择器TreeDataTemplateSelector
内容如下:
public class TreeDataTemplateSelector: DataTemplateSelector { public override DataTemplate SelectTemplate(object item, DependencyObject container) { TreeItemViewModel treeItem = item as TreeItemViewModel; var fe = container as FrameworkElement; if (treeItem.TreeType == TreeType.Folder) { return fe.FindResource("Folder") as DataTemplate; } return fe.FindResource("Node") as DataTemplate; } }
在 HierarchicalDataTemplate
中使用:
<HierarchicalDataTemplate x:Key="Folder" ItemTemplateSelector="{StaticResource TreeDataTemplateSelector}" DataType="{x:Type local:TreeItemViewModel}" ItemsSource="{Binding Children}"> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding Name}"/> <TextBlock Text="/"/> <TextBlock Text="{Binding TreeType}"/> </StackPanel> </HierarchicalDataTemplate>
运行效果如下:
以上就是 HierarchicalDataTemplate
多级样式的设置解决办法。