This article is currently in the process of being translated into French (~98% done).
TreeView, data binding and multiple templates
La vue arborescente de WPF supporte le binding de données, comme la plupart des contrôles WPF. Mais comme la vue arborescente est hiérarchisée par nature, un DataTemplate normal n'est pas suffisant le plus souvent. A la place, on utilise le HierarchicalDataTemplate qui nous permet d'avoir un template du nœud lui-même tout en contrôlant la propriété à utiliser comme source pour les items enfants de ce nœud.
Une vue arborescente bindée basique
Dans l'exemple suivant, je vous montrerai comment il est facile de commencer à travailler avec le 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; }
}
}
Dans le balisage XAML, j'ai spécifié HierarchicalDataTemplate pour le ItemTemplate de la vue arborescente. Je lui indique d'utiliser la propriété des Items pour trouver les items enfants en définissant la propriété ItemsSource du template. A l'intérieur, je définis le template actuel qui ne représente actuellement qu'un binding du TextBlock avec la propriété Title
Le premier exemple était très simple, en fait si simple que l'on aurait pu le faire manuellement au lieu de générer un jeu d'objets puis d'effectuer le binding. Toutefois, dès que cela devient un peu plus compliqué, les avantages du binding deviennent plus apparents.
Des templates multiples pour des types différents
Dans l'exemple suivant, j'ai pris un exemple plus complexe où je veut faire apparaître un arbre de familles et de leur membres. Une famille doit être représentée d'une façon, alors que chacun de ses membres a sa propre représentation. Pour ce faire, j'ai créé deux templates que j'ai spécifié en tant que ressources pour l'arbre (ou la fenêtre ou l'application - c'est vous qui voyez) et j'ai ensuite permis à la vue de choisir le template adapté en se basant sur le type de données sous-jacent.
Voici le code, l'explication arrive juste aprè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; }
}
}
Comme dit plus haut, les deux templates sont déclarés en tant que ressources de la vue arborescente ce qui permet à la vue de sélectionner le template approprié en se basant sur le type de données qu'elle doit afficher. Le template défini pour le type Family est un template hiérarchisé utilisant la propriété Members pour afficher les membres de la famille
Le template défini pour le type FamilyMember est un DataTemplate normal comme ce type n'a pas de nœuds enfants. Totuefois si on avait voulu que chaque FamilyMember ait une collection de ces enfants, voir également des enfants de ses enfants, alors on aurait utilisé un template hiérarchisé à la place.
Dans les deux templates, on utilise une image représentant soit une famille, soit un membre de la famille et ensuite on montre des données pertinentes à propos de cet item comme le nombre de membres de cette famille ou l'âge de la personne.
Dans le code-behind, on créé simplement 2 familles que l'on remplit avec une collection de membres puis on ajoute les familles à une liste qui sera utilisée comme source d'items par la vue arborescente.
Résumé
En utilisant le binding de données, la vue arborescente est très personnalisable et, avec la possibilité de spécifié plusieurs template pour afficher différents types de données, les possibilités sont presque sans fin.