WPF TreeView HierarchicalDataTemplate: enlace al objeto con varias colecciones secundarias

Estoy intentando que TreeView vincule mi colección para que todos los grupos muestren grupos nesteds y cada grupo muestre la entrada.

¿Cómo puedo usar HierarchicalDataTemplate para que TreeView procese tanto la colección SubGroups como las Entries?

Los grupos muestran subgrupos y entradas:

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

Objetos:


 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; } } } 

Datos de prueba:


 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; } } 

Una HierarchicalDataTemplate es una forma de decir ‘así es como se renderiza este tipo de objeto y aquí hay una propiedad que se puede sondear para encontrar los nodos secundarios bajo este objeto’

Por lo tanto, necesita una sola propiedad que devuelva los ‘hijos’ de este nodo. ej. (Si no puede hacer que tanto el Grupo como la Entrada deriven de un tipo de Nodo común)

 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; } } 

A continuación, no necesita una entrada HierDataTemplate ya que una entrada no tiene hijos. Por lo tanto, es necesario cambiar el XAML para usar la nueva propiedad Items y un DataTemplate para Entry:

           

Y esto es lo que parece. Captura de pantalla de salida

Creo que estás todo el camino hasta allí … con un poco de retrabajo deberías hacer que esto funcione con bastante facilidad …

Le sugiero que cree una clase abstracta base (o una interfaz, según lo que prefiera) y la herede / implemente tanto para la clase de Grupo como para la de Entrada …

De esta forma, puedes exponer una propiedad dentro de tu objeto Group

 public ObservableCollection Children { get; set; } 

^ en este punto, puede tomar una decisión si esto reemplaza sus listas de Subgrupos e Inscripciones, o simplemente los agrega juntos y los devuelve en el captador de propiedades …

Ahora todo lo que necesita es completar la colección Children con objetos Group o Entry, y HierarchicalDataTemplate se procesará correctamente cuando los objetos se coloquen en TreeView.

Un último pensamiento, si la entrada es siempre el ‘nivel inferior’ del árbol (es decir, no tiene hijos), entonces no es necesario definir una HierarchicalDataTemplate para el objeto de entrada, una DataTemplate será suficiente.

Espero que esto ayude 🙂

Aquí hay una implementación alternativa de la respuesta de Gishu que devuelve un IEnumerable lugar de un IList , y hace uso de la palabra clave yield para simplificar el código:

 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; } } } 

Esta publicación me ayudó cuando buscaba una solución para el mismo problema: http://blog.pmunin.com/2012/02/xaml-binding-to-compositecollection.html

utilizando MultiBinding y CompositeCollectionConverter ..

/ Recuerdos Anders