什么是带有 CollectionViewGroup 分组的惯用 XAML TreeView?
What's an idiomatic XAML TreeView with CollectionViewGroup groupings?
我有一个 TreeView
看起来像这样:
<TreeView Grid.Row="1" x:Name="InspectionResultsTreeView"
ItemsSource="{Binding Source={StaticResource InspectionTypeGroupViewSource}, Path=Groups}"
ItemTemplate="{StaticResource InspectionTypeGroupsTemplate}">
</TreeView>
ItemsSource
是一个键控资源,名称为 InspectionTypeGroupViewSource
:
<CollectionViewSource x:Key="InspectionTypeGroupViewSource" Source="{Binding Results}">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="Inspection.InspectionType" />
<PropertyGroupDescription PropertyName="Inspection" />
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
这个小东西的作用是取ViewModel的Results
属性:
private ObservableCollection<ICodeInspectionResult> _results;
public ObservableCollection<ICodeInspectionResult> Results
{
get { return _results; }
set { _results = value; OnPropertyChanged(); }
}
...并将其分组为两个级别 - 首先按 InspectionType
,然后按 Inspection
- 结果是一个 3 级层次结构,其中包含检查类型、检查,然后是单个检查结果.在这一点上,屏幕截图可能有助于可视化我猜:
因此,InspectionResultsTreeView
的 ItemTemplate
是另一个键控资源,名称为 InspectionTypeGroupsTemplate
- 即 bold "inspection type" 项:
<HierarchicalDataTemplate x:Key="InspectionTypeGroupsTemplate"
DataType="{x:Type CollectionViewGroup}"
ItemsSource="{Binding Items}"
ItemTemplate="{StaticResource InspectionGroupsTemplate}">
<StackPanel Orientation="Horizontal">
<TextBlock VerticalAlignment="Center"
Text="{Binding Name}"
FontWeight="Bold"
TextWrapping="NoWrap"/>
<TextBlock Margin="4,0,4,0"
VerticalAlignment="Center"
Text="{Binding ItemCount, StringFormat=({0})}"
TextWrapping="NoWrap"/>
</StackPanel>
</HierarchicalDataTemplate>
并且该模板的 ItemTemplate
是一个 InspectionGroupsTemplate
- 那是单独的检查,带有 "severity" 图标:
<HierarchicalDataTemplate x:Key="InspectionGroupsTemplate"
DataType="{x:Type CollectionViewGroup}"
ItemsSource="{Binding Items}"
ItemTemplate="{StaticResource InspectionResultTemplate}">
<StackPanel Orientation="Horizontal">
<Image Style="{StaticResource IconStyle}"
Source="{Binding Name, Converter={StaticResource InspectionIconConverter}}"
VerticalAlignment="Center" />
<TextBlock Margin="4"
VerticalAlignment="Center"
Text="{Binding Name, Converter={StaticResource InspectionDescriptionConverter}}"
TextWrapping="NoWrap"/>
<TextBlock Margin="0,4,0,4"
VerticalAlignment="Center"
Text="{Binding ItemCount, StringFormat=({0})}"
TextWrapping="NoWrap"/>
</StackPanel>
</HierarchicalDataTemplate>
最后,这个分组的ItemTemplate
是一个InspectionResultTemplate
,对于每个单独的检查结果:
<DataTemplate x:Key="InspectionResultTemplate"
DataType="{x:Type inspections:ICodeInspectionResult}">
<StackPanel Orientation="Horizontal">
<TextBlock VerticalAlignment="Center"
Margin="4"
Text="{Binding Name}"
TextWrapping="NoWrap"/>
</StackPanel>
</DataTemplate>
ICodeInspectionResult
接口有一个 string Name
属性,我在这里使用;这个 Name
与分组级别中使用的 Name
不同,后者是 object CollectionViewGroup.Name
- Name
的基础类型是分组的类型,因此级别 1是一个InspectionType
,2级是一个Inspection
。
问题是我使用的转换器比我认为需要的要多,以转换此 object Name
并访问我需要访问和显示的成员...但是,我需要显示每个分组中的项目数,因此 DataType
应该是 CollectionViewGroup
... 对吗?
如何在不借助转换器来显示所有需要显示的内容的情况下执行此操作? 应该如何完成?我能找到的每个 TreeView
/ CollectionViewGroup
教程都是一个微不足道的实现。
您遇到了 XAML 的标志性问题:它几乎 太 结构化了。
最 惯用的解决方案是编写自定义 WPF 用户控件。 (如何以及在其中包含什么由您决定。)WPF 用户控件的目标是消除重复的 XAML 标记和逻辑。您可以将 Converter
包含在用户控件中,并从主控件中删除转换器。
在WPF中创建UserControl
对象的教程很多,这里就不赘述了。
至于 Converter
问题:这是 几乎 最惯用的方式。每个转换器都是可重复使用的,并且只专注于一种源类型。除了考虑将支持相同源类型的转换器合并在一起之外,您无能为力。 (转换器有一个 Type targetType
参数和一个 object parameter
是有原因的。)
我有一个 TreeView
看起来像这样:
<TreeView Grid.Row="1" x:Name="InspectionResultsTreeView"
ItemsSource="{Binding Source={StaticResource InspectionTypeGroupViewSource}, Path=Groups}"
ItemTemplate="{StaticResource InspectionTypeGroupsTemplate}">
</TreeView>
ItemsSource
是一个键控资源,名称为 InspectionTypeGroupViewSource
:
<CollectionViewSource x:Key="InspectionTypeGroupViewSource" Source="{Binding Results}">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="Inspection.InspectionType" />
<PropertyGroupDescription PropertyName="Inspection" />
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
这个小东西的作用是取ViewModel的Results
属性:
private ObservableCollection<ICodeInspectionResult> _results;
public ObservableCollection<ICodeInspectionResult> Results
{
get { return _results; }
set { _results = value; OnPropertyChanged(); }
}
...并将其分组为两个级别 - 首先按 InspectionType
,然后按 Inspection
- 结果是一个 3 级层次结构,其中包含检查类型、检查,然后是单个检查结果.在这一点上,屏幕截图可能有助于可视化我猜:
因此,InspectionResultsTreeView
的 ItemTemplate
是另一个键控资源,名称为 InspectionTypeGroupsTemplate
- 即 bold "inspection type" 项:
<HierarchicalDataTemplate x:Key="InspectionTypeGroupsTemplate"
DataType="{x:Type CollectionViewGroup}"
ItemsSource="{Binding Items}"
ItemTemplate="{StaticResource InspectionGroupsTemplate}">
<StackPanel Orientation="Horizontal">
<TextBlock VerticalAlignment="Center"
Text="{Binding Name}"
FontWeight="Bold"
TextWrapping="NoWrap"/>
<TextBlock Margin="4,0,4,0"
VerticalAlignment="Center"
Text="{Binding ItemCount, StringFormat=({0})}"
TextWrapping="NoWrap"/>
</StackPanel>
</HierarchicalDataTemplate>
并且该模板的 ItemTemplate
是一个 InspectionGroupsTemplate
- 那是单独的检查,带有 "severity" 图标:
<HierarchicalDataTemplate x:Key="InspectionGroupsTemplate"
DataType="{x:Type CollectionViewGroup}"
ItemsSource="{Binding Items}"
ItemTemplate="{StaticResource InspectionResultTemplate}">
<StackPanel Orientation="Horizontal">
<Image Style="{StaticResource IconStyle}"
Source="{Binding Name, Converter={StaticResource InspectionIconConverter}}"
VerticalAlignment="Center" />
<TextBlock Margin="4"
VerticalAlignment="Center"
Text="{Binding Name, Converter={StaticResource InspectionDescriptionConverter}}"
TextWrapping="NoWrap"/>
<TextBlock Margin="0,4,0,4"
VerticalAlignment="Center"
Text="{Binding ItemCount, StringFormat=({0})}"
TextWrapping="NoWrap"/>
</StackPanel>
</HierarchicalDataTemplate>
最后,这个分组的ItemTemplate
是一个InspectionResultTemplate
,对于每个单独的检查结果:
<DataTemplate x:Key="InspectionResultTemplate"
DataType="{x:Type inspections:ICodeInspectionResult}">
<StackPanel Orientation="Horizontal">
<TextBlock VerticalAlignment="Center"
Margin="4"
Text="{Binding Name}"
TextWrapping="NoWrap"/>
</StackPanel>
</DataTemplate>
ICodeInspectionResult
接口有一个 string Name
属性,我在这里使用;这个 Name
与分组级别中使用的 Name
不同,后者是 object CollectionViewGroup.Name
- Name
的基础类型是分组的类型,因此级别 1是一个InspectionType
,2级是一个Inspection
。
问题是我使用的转换器比我认为需要的要多,以转换此 object Name
并访问我需要访问和显示的成员...但是,我需要显示每个分组中的项目数,因此 DataType
应该是 CollectionViewGroup
... 对吗?
如何在不借助转换器来显示所有需要显示的内容的情况下执行此操作? 应该如何完成?我能找到的每个 TreeView
/ CollectionViewGroup
教程都是一个微不足道的实现。
您遇到了 XAML 的标志性问题:它几乎 太 结构化了。
最 惯用的解决方案是编写自定义 WPF 用户控件。 (如何以及在其中包含什么由您决定。)WPF 用户控件的目标是消除重复的 XAML 标记和逻辑。您可以将 Converter
包含在用户控件中,并从主控件中删除转换器。
在WPF中创建UserControl
对象的教程很多,这里就不赘述了。
至于 Converter
问题:这是 几乎 最惯用的方式。每个转换器都是可重复使用的,并且只专注于一种源类型。除了考虑将支持相同源类型的转换器合并在一起之外,您无能为力。 (转换器有一个 Type targetType
参数和一个 object parameter
是有原因的。)