开发者

WPF TreeView - Binding to ViewModels with nested collections AND "Static nodes"

开发者 https://www.devze.com 2023-02-10 07:28 出处:网络
I\'ve looked at the similar questions regarding TreeView data binding to nested collections, and I\'ve read several \"Josh \'n Bea\" articles about this topic, but my design differs in that i have \"s

I've looked at the similar questions regarding TreeView data binding to nested collections, and I've read several "Josh 'n Bea" articles about this topic, but my design differs in that i have "static" TreeViewItems that serve as collapsible containers fo开发者_C百科r the nested collection items. It's best to illustrate what I'm looking for.

Given these ViewModel classes:

namespace TreeViewSample
{
    public class ApplicationViewModel
    {
        public ApplicationViewModel() { Projects = new List<ProjectViewModel>(); }
        public IEnumerable<ProjectViewModel> Projects { get; set; }
    }

    public class ProjectViewModel
    {
        public ProjectViewModel() { Maps = new List<MapViewModel>(); }
        public string Name { get; set; }
        public IEnumerable<MapViewModel> Maps { get; set; }
    }

    public class MapViewModel
    {
        public MapViewModel() { Tables = new List<TableViewModel>(); }
        public string Name { get; set; }
        public IEnumerable<TableViewModel> Tables { get; set; }
    }

    public class TableViewModel
    {
        public TableViewModel() { Fields = new List<FieldViewModel>(); }
        public string Name { get; set; }
        public IEnumerable<FieldViewModel> Fields { get; set; }
    }

    public class FieldViewModel
    {
        public string Name { get; set; }
    }
}

This is the result i want:

WPF TreeView - Binding to ViewModels with nested collections AND "Static nodes"

Can anyone help me with the XAML for this TreeView? I thought i understood how HierarchicalDataTemplates work, but the "static" container nodes ("Tables", "Fields", "Maps") seem to confuse me.

Thank you and have a pleasant day!


I think you're gonna have to create HierarchicalDataTemplates for the "Static" nodes as well. And since ItemsSource of an HierarchicalDataTemplate expects a Collection you can create these collections in Xaml like this

Namespaces

xmlns:coll="clr-namespace:System.Collections;assembly=mscorlib"
xmlns:sys="clr-namespace:System;assembly=mscorlib"

Collections

<coll:ArrayList x:Key="MapCollection">
    <sys:String>Maps</sys:String>
</coll:ArrayList>
<coll:ArrayList x:Key="TableCollection">
    <sys:String>Tables</sys:String>
</coll:ArrayList>
<coll:ArrayList x:Key="FieldCollection">
    <sys:String>Fields</sys:String>
</coll:ArrayList>

The problem with this solution is that when you set e.g. MapCollection as ItemsSource for a HierarchicalDataTemplate, you won't have access to the Maps Collection Property in the next level so you'll have to climb up the Visual Tree to get a hold of it like

ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type TreeViewItem}},
                      Path=DataContext.Maps}"

Using this approach, your HierarchicalDataTemplates can look like this

<!-- Field Templates -->
<HierarchicalDataTemplate x:Key="FieldsTemplate">
    <TextBlock Text="{Binding Name}"/>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate x:Key="FieldTemplate"
                          ItemTemplate="{StaticResource FieldsTemplate}"
                          ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type TreeViewItem}},
                                                Path=DataContext.Fields}">
    <TextBlock Text="{Binding}"/>
</HierarchicalDataTemplate>

<!-- Table Templates -->
<HierarchicalDataTemplate x:Key="TablesTemplate"
                          ItemTemplate="{StaticResource FieldTemplate}"
                          ItemsSource="{Binding Source={StaticResource FieldCollection}}">
    <TextBlock Text="{Binding Name}"/>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate x:Key="TableTemplate"
                          ItemTemplate="{StaticResource TablesTemplate}"
                          ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type TreeViewItem}},
                                                Path=DataContext.Tables}">
    <TextBlock Text="{Binding}"/>
</HierarchicalDataTemplate>

<!-- Map Templates -->
<HierarchicalDataTemplate x:Key="MapsTemplate"
                          ItemTemplate="{StaticResource TableTemplate}"
                          ItemsSource="{Binding Source={StaticResource TableCollection}}">
    <TextBlock Text="{Binding Name}"/>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate x:Key="MapTemplate"
                          ItemTemplate="{StaticResource MapsTemplate}"
                          ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type TreeViewItem}},
                                                Path=DataContext.Maps}">
    <TextBlock Text="{Binding}"/>
</HierarchicalDataTemplate>

<!-- Project Template -->
<HierarchicalDataTemplate x:Key="ProjectDataTemplate"
                          ItemTemplate="{StaticResource MapTemplate}"
                          ItemsSource="{Binding Source={StaticResource MapCollection}}">
    <TextBlock Text="{Binding Path=Name}"/>
</HierarchicalDataTemplate>

TreeView

<TreeView Name="treeView"
          ItemTemplate="{StaticResource ProjectDataTemplate}"
          ItemsSource="{Binding Projects}"/>
0

精彩评论

暂无评论...
验证码 换一张
取 消