我知道有很多在 wpf 中使用树视图的例子。我知道这很难相信,但我认为我有一个合理的问题尚未被 StackOverflow 上关于树视图的无数问题所解决。
(TL;DR版本:尝试了很多东西。看了很多网站。有复杂的树结构。寻找一种简单的方法来实现所需的树结果。底部的问题。)
所以这里...
当然,Philipp Sumi有关于使用 TreeViews 的非常有用的帖子。
所需输出的要点是不同类型的项目在其各自的标题下呈现,并且对象可以在不同的位置表示两次。建议单独使用 DataTemplateSelector 不会为我提供所需的TreeView
.
期望的输出:
Root
|--Header A (People)
|---Person A1 (Jane)
|---Person A2 (Steve)
|--Header B (Cars)
|---Car B1 (Red Car)
|---Car B2 (Blue Car)
|---Person A1 (Jane)
|---Person A3 (Jon)
注意:A3 是 Jon Skeet ,SO 的 Chuck Noris
我的方法的第一部分基本上是使用 aCompositeCollection
虽然我实际上并没有使用它。尽管如此,这篇文章似乎表明它不会解决我的问题。作为人,即。史蒂夫,他的数据中没有其他人、汽车或任何其他对象,所以他是一个最终项目。
查看型号:
我绑定的是:
public ObservableCollection<object> Children
{
get
{
ObservableCollection<object> childNodes = new ObservableCollection<object>();
foreach (var person in PeopleCollection)
childNodes.Add(person);
foreach (var car in CarCollection)
childNodes.Add(car);
return childNodes;
}
}
模板选择器:
我们必须在 TreeView 中管理多种类型的对象,所以我使用 DataTemplateSelector,如下所示:
class MyTemplateSelector : DataTemplateSelector
{
public HierarchicalDataTemplate CarTemplate { get; set; }
public HierarchicalDataTemplate PeopleTemplate { get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
if (item.GetType() == typeof(Car))
return CarTemplate;
if (item.GetType() == typeof(Person))
return (PeopleTemplate);
return (null);
}
}
XAML:
最后,有一些 XAML 可以很好地将它们捆绑在一起。
<UserControl.Resources>
<HierarchicalDataTemplate x:Key="m_CarTemplate"
DataType="{x:Type local:Car}"
ItemsSource="{Binding People}" >
<TextBlock Text="{Binding CarColor}" />
</HierarchicalDataTemplate>
<HierarchicalDataTemplate x:Key="m_PeopleTemplate"
DataType="{x:Type local:Person}">
<TextBlock Text="{Binding PersonName}" />
</HierarchicalDataTemplate>
<local:ProjectTemplateSelector
CarTemplate="{StaticResource m_CarTemplate}"
PeopleTemplate ="{StaticResource m_PeopleTemplate}"
x:Key="myTemplateSelector"/>
</UserControl.Resources>
在 XAML 中再往下一点:
<TreeView Width="Auto" Height="Auto" HorizontalAlignment="Left"
VerticalAlignment="Top" Margin="0,0,0,0" Name="m_TreeView"
ItemsSource="{Binding ViewModel.Children}"
ItemTemplateSelector="{StaticResource myTemplateSelector}"
/>
潜在的解决方案:
Philipp 方法的主要挫折是我真的只想在第一级设置类别,理想情况下是通过,<TreeViewItem Header="Cars" />
但似乎它会失败。接下来,我没有这些类别级别项目的项目,即。汽车和人,只是字符串。我想我可以制作这些占位符对象,并给它们各自的集合,而不是在我的 viewModel 上用它们制作属性,但这似乎有点过分只是为了获得一些标题......特别是因为已经存在。
第二种选择是CompositeCollection 方法,有一个很好的例子,但我不完全确定它会解决我的问题。一方面,我没有看到它在 TreeView 中使用过,所以我不确定它是否会适当地应用在那里,我想使用 TreeView 来保留数据的层次结构。
最后,我尝试了自己的变体,在其中HierarchicalDataTemplate
添加了 a<TreeViewItem Header="Cars" />
但这不起作用,因为每辆 Car 都有自己的标题。
问题
主要问题:通过绑定来实现所需的 TreeView 结构的适当方法是什么?因此产生的结果是所有汽车都显示在 Cars 标题下,People 显示在 People 标题下,除了位于 Cars.PeopleCollection 中的人也显示为相应 Car 对象的子对象。
第二个问题:专门为 TreeViewItems 创建一个 Wrapper 类是一种常见且适当的方法吗?那是我应该做的吗?正如我在 Philipp 的潜在解决方案中所描述的那样。
我还应该提到,鉴于我在这里描述的解决方案,代码可以编译。问题是没有标题。下一个问题是在我将人员添加到汽车后,然后尝试扩展汽车,我收到以下错误:Must disconnect specified child from current parent Visual before attaching to new parent Visual.
我认为这是这行代码的产物:ObservableCollection<object> childNodes = new ObservableCollection<object>();
但坦率地说,它已经晚了,我很累,所以我可以不要想出合适的方法来做到这一点,也许 CompositeCollection 是我需要的。