一、问题场景
日常为 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
多级样式的设置解决办法。