WPF TreeView HierarchicalDataTemplate – associazione all’object con più raccolte secondarie

Sto cercando di ottenere un TreeView per bind la mia collezione in modo che tutti i gruppi mostrino gruppi nidificati e ogni gruppo mostrerà la voce.

Come posso utilizzare HierarchicalDataTemplate modo che TreeView elabori sia la raccolta di sottogruppi che di voci?

I gruppi mostrano sottogruppi e voci:

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

Oggetti:


 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 SubGroups { get; set; } public IList Entries { get; set; } } } 

Dati di test:


 namespace DrillDownView { public class TestData { public IList Groups = new List(); public void Load() { Group grp1 = new Group() { Key = 1, Name = "Group 1", SubGroups = new List(), Entries = new List() }; Group grp2 = new Group() { Key = 2, Name = "Group 2", SubGroups = new List(), Entries = new List() }; Group grp3 = new Group() { Key = 3, Name = "Group 3", SubGroups = new List(), Entries = new List() }; Group grp4 = new Group() { Key = 4, Name = "Group 4", SubGroups = new List(), Entries = new List() }; //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:


                     

XAML.CS:


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

Un HierarchicalDataTemplate è un modo per dire ‘questo è come si esegue il rendering di questo tipo di object e qui è una proprietà che può essere esplorata per trovare i nodes figlio sotto questo object’

Pertanto è necessaria una singola proprietà che restituisca i “figli” di questo nodo. es. (Se non puoi fare in modo che Gruppo e Entrata derivino da un tipo di nodo comune)

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

Quindi non è necessario un HierDataTemplate per la voce poiché una voce non ha figli. Quindi è necessario modificare XAML per utilizzare la nuova proprietà Items e un DataTemplate per l’Entry:

           

Ed ecco come appare. Screenshot dell'output

Penso che tu sia la maggior parte del modo lì … con un po ‘di rilavorazione dovresti farlo funzionare abbastanza facilmente …

Ti suggerisco di creare una class astratta di base (o un’interfaccia, quella che preferisci) e di ereditarla / implementarla sia per la class di gruppo che per quella di entrata …

In questo modo, puoi esporre una proprietà all’interno dell’object del tuo gruppo

 public ObservableCollection Children { get; set; } 

^ a questo punto, puoi prendere una decisione se questo sostituisce i tuoi elenchi di sottogruppi e voci, o semplicemente li aggiunge e li restituisce nel getter della proprietà …

Ora tutto ciò che serve è compilare la raccolta Children con oggetti Group o Entry e HierarchicalDataTemplate eseguirà correttamente il rendering quando gli oggetti vengono posizionati nel TreeView.

Un ultimo pensiero, se Entry è sempre il ‘livello inferiore’ dell’albero (cioè non ha figli), quindi non è necessario definire un HierarchicalDataTemplate per l’object Entry, un DataTemplate sarà sufficiente.

Spero che questo ti aiuti 🙂

Ecco un’implementazione alternativa della risposta di Gishu che restituisce un object IEnumerable piuttosto che un IList e utilizza la parola chiave yield per semplificare il codice:

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

Questo post mi ha aiutato quando cercavo una soluzione per lo stesso problema: http://blog.pmunin.com/2012/02/xaml-binding-to-compositecollection.html

usando MultiBinding e CompositeCollectionConverter ..

/ Saluti Anders