多个TreeViewItem标头按类型分隔

时间:2013-08-14 09:23:30

标签: c# wpf treeview treeviewitem

我知道有很多在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:

最后,有一些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就是我所需要的。

1 个答案:

答案 0 :(得分:1)

要添加类别标题,我会看到两种可能的解决方案。

第一个是创建一个对象“Category”并将其添加到您的children集合中。然后,创建随之而来的dataTemplate。

另一个解决方案是:

1-创建一个收集类别名称和汽车或人员集合的班级

2-为此类创建一个dataTemplate(一个用于显示类别名称的文本块和一个用于显示具有相应dataTemplate的集合的树视图)

3-您的孩子列表将是此对象的列表。