WPF TreeView - Binding to ViewModels with nested collections AND "Static nodes"
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:
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 HierarchicalDataTemplate
s 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 HierarchicalDataTemplate
s 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}"/>
精彩评论