This article is currently in the process of being translated into Spanish (~98% done).
TreeView, data binding and multiple templates
El TreeView de WPF admite el enlace de datos, al igual que casi todos los demás controles de WPF, pero debido a que el TreeView es de naturaleza jerárquica, es normal DataTemplate a menudo no será suficiente. En su lugar, usamos HierarchicalDataTemplate, que nos permite modelar el nodo del árbol en sí, mientras controlamos qué propiedad usar como fuente para los elementos secundarios del nodo.
Una vista de árbol básica enlazada a datos.
En el siguiente ejemplo, le mostraré lo fácil que es comenzar con HierarchicalDataTemplate:
<Window x:Class="WpfTutorialSamples.TreeView_control.TreeViewDataBindingSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:self="clr-namespace:WpfTutorialSamples.TreeView_control"
Title="TreeViewDataBindingSample" Height="150" Width="200">
<Grid Margin="10">
<TreeView Name="trvMenu">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate DataType="{x:Type self:MenuItem}" ItemsSource="{Binding Items}">
<TextBlock Text="{Binding Title}" />
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Grid>
</Window>
using System;
using System.Collections.Generic;
using System.Windows;
using System.IO;
using System.Collections.ObjectModel;
namespace WpfTutorialSamples.TreeView_control
{
public partial class TreeViewDataBindingSample : Window
{
public TreeViewDataBindingSample()
{
InitializeComponent();
MenuItem root = new MenuItem() { Title = "Menu" };
MenuItem childItem1 = new MenuItem() { Title = "Child item #1" };
childItem1.Items.Add(new MenuItem() { Title = "Child item #1.1" });
childItem1.Items.Add(new MenuItem() { Title = "Child item #1.2" });
root.Items.Add(childItem1);
root.Items.Add(new MenuItem() { Title = "Child item #2" });
trvMenu.Items.Add(root);
}
}
public class MenuItem
{
public MenuItem()
{
this.Items = new ObservableCollection<MenuItem>();
}
public string Title { get; set; }
public ObservableCollection<MenuItem> Items { get; set; }
}
}
En el marcado XAML, he especificado un HierarchicalDataTemplate para ItemTemplate de TreeView. Le indico que use la propiedad Items para encontrar elementos secundarios, estableciendo la propiedad ItemsSource de la plantilla, y dentro de ella defino la plantilla real, que por ahora solo consiste en un TextBlock vinculado a la propiedad Title .
Este primer ejemplo fue muy simple, de hecho tan simple que bien podríamos haber agregado los elementos TreeView manualmente, en lugar de generar un conjunto de objetos y luego vinculante a ellos. Sin embargo, tan pronto como las cosas se vuelven un poco más complicadas, las ventajas de usar enlaces de datos se vuelven más obvias.
Múltiples plantillas para diferentes tipos.
En el siguiente ejemplo, he tomado un caso un poco más complejo, donde quiero mostrar un árbol de familias y sus miembros. Una familia debe estar representada de una manera, mientras que cada uno de sus miembros debe mostrarse de otra manera. Lo logro creando dos plantillas diferentes y especificándolas como recursos de árbol (o la ventana o la aplicación, eso realmente depende de usted), y luego permitir que TreeView elija la plantilla correcta en función del tipo de datos subyacentes.
Aquí está el código, la explicación seguirá inmediatamente después:
<Window x:Class="WpfTutorialSamples.TreeView_control.TreeViewMultipleTemplatesSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:self="clr-namespace:WpfTutorialSamples.TreeView_control"
Title="TreeViewMultipleTemplatesSample" Height="200" Width="250">
<Grid Margin="10">
<TreeView Name="trvFamilies">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type self:Family}" ItemsSource="{Binding Members}">
<StackPanel Orientation="Horizontal">
<Image Source="/WpfTutorialSamples;component/Images/group.png" Margin="0,0,5,0" />
<TextBlock Text="{Binding Name}" />
<TextBlock Text=" [" Foreground="Blue" />
<TextBlock Text="{Binding Members.Count}" Foreground="Blue" />
<TextBlock Text="]" Foreground="Blue" />
</StackPanel>
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type self:FamilyMember}">
<StackPanel Orientation="Horizontal">
<Image Source="/WpfTutorialSamples;component/Images/user.png" Margin="0,0,5,0" />
<TextBlock Text="{Binding Name}" />
<TextBlock Text=" (" Foreground="Green" />
<TextBlock Text="{Binding Age}" Foreground="Green" />
<TextBlock Text=" years)" Foreground="Green" />
</StackPanel>
</DataTemplate>
</TreeView.Resources>
</TreeView>
</Grid>
</Window>
using System;
using System.Collections.Generic;
using System.Windows;
using System.Collections.ObjectModel;
namespace WpfTutorialSamples.TreeView_control
{
public partial class TreeViewMultipleTemplatesSample : Window
{
public TreeViewMultipleTemplatesSample()
{
InitializeComponent();
List<Family> families = new List<Family>();
Family family1 = new Family() { Name = "The Doe's" };
family1.Members.Add(new FamilyMember() { Name = "John Doe", Age = 42 });
family1.Members.Add(new FamilyMember() { Name = "Jane Doe", Age = 39 });
family1.Members.Add(new FamilyMember() { Name = "Sammy Doe", Age = 13 });
families.Add(family1);
Family family2 = new Family() { Name = "The Moe's" };
family2.Members.Add(new FamilyMember() { Name = "Mark Moe", Age = 31 });
family2.Members.Add(new FamilyMember() { Name = "Norma Moe", Age = 28 });
families.Add(family2);
trvFamilies.ItemsSource = families;
}
}
public class Family
{
public Family()
{
this.Members = new ObservableCollection<FamilyMember>();
}
public string Name { get; set; }
public ObservableCollection<FamilyMember> Members { get; set; }
}
public class FamilyMember
{
public string Name { get; set; }
public int Age { get; set; }
}
}
Como se mencionó, las dos plantillas se declaran como parte de los recursos de TreeView, lo que permite que TreeView seleccione la plantilla adecuada según el tipo de datos que está a punto de mostrar. La plantilla definida para el tipo Familia es una plantilla jerárquica, que utiliza la propiedad Miembros para mostrar a sus familiares.
La plantilla definida para el tipo FamilyMember es un DataTemplate normal, ya que este tipo no tiene miembros secundarios. Sin embargo, si nosotros hubiéramos querido que cada miembro de la familia mantuviera una colección de sus hijos y tal vez los hijos de sus hijos, entonces habríamos utilizado una plantilla jerárquica en su lugar.
En ambas plantillas, utilizamos una imagen que representa a una familia o un miembro de la familia, y luego mostramos algunos datos interesantes al respecto, como la cantidad de miembros de la familia o la edad de la persona.
En el código subyacente, simplemente creamos dos instancias de Familia, llenamos cada una de ellas con un conjunto de miembros y luego agregamos cada una de las familias a una lista, que se usa como fuente de elementos para TreeView.
Resumen
Resumen