WPF TreeView HierarchicalDataTemplate – 绑定到具有多个子集合的对象

我试图让TreeView绑定我的集合,以便所有组显示嵌套组,每个组将显示条目。

我如何使用HierarchicalDataTemplate以便TreeView将处理SubGroups和Entries集合?

组显示子组和条目:

 Example: Group1 --Entry --Entry Group2 --Group4 ----Group1 ------Entry ------Entry ----Entry ----Entry --Entry --Entry Group3 --Entry --Entry 

对象:


 namespace TaskManager.Domain { public class Entry { public int Key { get; set; } public string Name { get; set; } } } namespace TaskManager.Domain { public class Group { public int Key { get; set; } public string Name { get; set; } public IList<Group> SubGroups { get; set; } public IList<Entry> Entries { get; set; } } } 

testing数据:


 namespace DrillDownView { public class TestData { public IList<Group> Groups = new List<Group>(); public void Load() { Group grp1 = new Group() { Key = 1, Name = "Group 1", SubGroups = new List<Group>(), Entries = new List<Entry>() }; Group grp2 = new Group() { Key = 2, Name = "Group 2", SubGroups = new List<Group>(), Entries = new List<Entry>() }; Group grp3 = new Group() { Key = 3, Name = "Group 3", SubGroups = new List<Group>(), Entries = new List<Entry>() }; Group grp4 = new Group() { Key = 4, Name = "Group 4", SubGroups = new List<Group>(), Entries = new List<Entry>() }; //grp1 grp1.Entries.Add(new Entry() { Key=1, Name="Entry number 1" }); grp1.Entries.Add(new Entry() { Key=2, Name="Entry number 2" }); grp1.Entries.Add(new Entry() { Key=3,Name="Entry number 3" }); //grp2 grp2.Entries.Add(new Entry(){ Key=4, Name = "Entry number 4"}); grp2.Entries.Add(new Entry(){ Key=5, Name = "Entry number 5"}); grp2.Entries.Add(new Entry(){ Key=6, Name = "Entry number 6"}); //grp3 grp3.Entries.Add(new Entry(){ Key=7, Name = "Entry number 7"}); grp3.Entries.Add(new Entry(){ Key=8, Name = "Entry number 8"}); grp3.Entries.Add(new Entry(){ Key=9, Name = "Entry number 9"}); //grp4 grp4.Entries.Add(new Entry(){ Key=10, Name = "Entry number 10"}); grp4.Entries.Add(new Entry(){ Key=11, Name = "Entry number 11"}); grp4.Entries.Add(new Entry(){ Key=12, Name = "Entry number 12"}); grp4.SubGroups.Add(grp1); grp2.SubGroups.Add(grp4); Groups.Add(grp1); Groups.Add(grp2); Groups.Add(grp3); } } } 

XAML:


 <Window x:Class="DrillDownView.Window2" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:TaskManager.Domain;assembly=TaskManager.Domain" Title="Window2" Height="300" Width="300"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" /> </Grid.ColumnDefinitions> <TreeView Name="GroupView" Grid.Row="0" Grid.Column="0" ItemsSource="{Binding}"> <TreeView.Resources> <HierarchicalDataTemplate DataType="{x:Type local:Group}" ItemsSource="{Binding SubGroups}"> <TextBlock Text="{Binding Path=Name}" /> </HierarchicalDataTemplate> <HierarchicalDataTemplate DataType="{x:Type local:Entry}" ItemsSource="{Binding Entries}"> <TextBlock Text="{Binding Path=Name}" /> </HierarchicalDataTemplate> </TreeView.Resources> </TreeView> </Grid> </Window> 

XAML.CS:


 public partial class Window2 : Window { public Window2() { InitializeComponent(); LoadView(); } private void LoadView() { TestData data = new TestData(); data.Load(); GroupView.ItemsSource = data.Groups; } } 

HierarchicalDataTemplate是一种说法,“这是如何呈现这种types的对象,这里是一个属性,可以被探测到find这个对象下的子节点”

因此,您需要一个返回此节点的“子”的属性。 例如(如果不能使Group和Entry都来自一个公共节点types)

 public class Group{ .... public IList<object> Items { get { IList<object> childNodes = new List<object>(); foreach (var group in this.SubGroups) childNodes.Add(group); foreach (var entry in this.Entries) childNodes.Add(entry); return childNodes; } } 

接下来,由于条目没有子项,因此不需要HierDataTemplate进行input。 因此,XAML需要更改为使用新的Items属性和DataTemplate进行input:

 <TreeView Name="GroupView" Grid.Row="0" Grid.Column="0" ItemsSource="{Binding}"> <TreeView.Resources> <HierarchicalDataTemplate DataType="{x:Type local:Group}" ItemsSource="{Binding Items}"> <TextBlock Text="{Binding Path=Name}" /> </HierarchicalDataTemplate> <DataTemplate DataType="{x:Type local:Entry}" > <TextBlock Text="{Binding Path=Name}" /> </DataTemplate> </TreeView.Resources> </TreeView> 

这就是这个样子 输出的屏幕截图

我认为你是那里的大部分…有一点返工,你应该很容易地得到这个工作…

我build议你创build一个基本的抽象类(或一个接口,无论你喜欢什么),并inheritance/实施组和类入门…

这样,你可以在你的Group对象中公开一个属性

 public ObservableCollection<ITreeViewItem> Children { get; set; } 

^在这一点上,你可以做出一个决定,如果这取代了你的SubGroups和Entries的列表,或者只是将它们附加在一起,并将它们返回给属性getter …

现在,您只需要使用Group或Entry对象填充Children集合,并且在将对象放置在TreeView中时, HierarchicalDataTemplate将正确呈现。

最后一个想法是,如果Entry始终是树的“底层”(即没有子节点),那么您不需要为Entry对象定义HierarchicalDataTemplate ,那么DataTemplate就足够了。

希望这可以帮助 :)

这里是Gishu的答案的另一个实现,它返回一个IEnumerable而不是IList ,并使用yield关键字来简化代码:

 public class Group { ... public IEnumerable<object> Items { get { foreach (var group in this.SubGroups) yield return group; foreach (var entry in this.Entries) yield return entry; } } } 

这篇文章帮助我解决同一问题的解决scheme: http : //blog.pmunin.com/2012/02/xaml-binding-to-compositecollection.html

使用MultiBinding和CompositeCollectionConverter ..

/关心安德斯