我知道有很多在wpf中使用treeview的例子。我知道很难相信,但我认为我有一个合法的问题尚未解决有关StackOverflow上已有的关于树视图的无数问题。
( TL; DR 版本:尝试了很多东西。看了很多网站。有复杂的树结构。寻找一种简单的方法来实现所需的树结果。问题在底部。)
所以这里......
我已阅读Josh's famous post on TreeViews
当然,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 the Chuck Noris of SO
我的方法的第一部分是基本上使用CompositeCollection
,虽然我实际上并没有使用它。然而this post似乎暗示它不会解决我的问题。作为人,即。史蒂夫,他的数据中没有其他人,汽车或任何其他对象,因此他是最终项目。
我对此的约束是:
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可以很好地捆绑这些。
<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上为它们提供各自的集合而不是make属性,但这似乎有点过分只是为了得到一些标题...特别是因为已经存在。
第二种选择是CompositeCollection approach, with a good example,但我不完全确定它会解决我的问题。首先,我没有看到在TreeView中使用它,所以我不确定它是否适用于那里,我想使用TreeView来保留数据的分层特性。
最后,我尝试了自己的变体,HierarchicalDataTemplate
我添加<TreeViewItem Header="Cars" />
,但这不起作用,因为每辆车都有自己的标题。
主要问题:通过绑定实现TreeView所需结构的适当方法是什么?因此产生一个结果,其中所有汽车都显示在汽车标题下,People Header下的人员,除了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就是我所需要的。
答案 0 :(得分:1)
要添加类别标题,我会看到两种可能的解决方案。
第一个是创建一个对象“Category”并将其添加到您的children集合中。然后,创建随之而来的dataTemplate。
另一个解决方案是:
1-创建一个收集类别名称和汽车或人员集合的班级
2-为此类创建一个dataTemplate(一个用于显示类别名称的文本块和一个用于显示具有相应dataTemplate的集合的树视图)
3-您的孩子列表将是此对象的列表。