This article has been localized into Russian by the community.
TreeView, привязка данных и несколько шаблонов
WPF TreeView поддерживает привязку данных, как и почти все другие элементы управления WPF, но поскольку TreeView по своей природе является иерархическим, обычного шаблона данных часто бывает недостаточно. Вместо этого мы используем HierarchicalDataTemplate, который позволяет нам создавать шаблоны как для самого узла дерева, так и контролировать какое свойство использовать в качестве источника для дочерних элементов узла.
Основная привязка данных в TreeView
В следующем примере я покажу вам, как легко начать работу с 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; }
}
}
В разметке XAML я определил HierarchicalDataTemplate для ItemTemplate TreeView. Для свойства ItemsSource шаблона я устанавливаю значение равное Items, тем самым использую это свойство для поиска дочерних элементов, и уже внутри него я применяю фактический шаблон который на данный момент состоит только из TextBlock, привязанного к свойству Title.
Этот пример был очень простым, на самом деле мы могли бы просто добавить элементы TreeView вручную вместо генерации набора объектов и последующей привязкой к ним. Однако, как только все становится немного сложнее, преимущества использования привязок данных становятся более очевидными.
Несколько шаблонов для разных типов
В следующем примере я взял более сложный случай, где я хочу показать дерево семей и их членов. Семья должна быть представлена одним способом, а каждый из ее членов - другим. Этого можно достичь, создав два разных шаблона и указав их в качестве ресурсов TreeView (или Window или Application - это зависит от вас), а затем позволить TreeView выбрать правильный шаблон на основе базового типа данных.
Вот код - после него сразу следует объяснение:
<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; }
}
}
Как уже упоминалось ранее, два шаблона объявлены как часть ресурсов TreeView, что позволяет TreeView выбрать соответствующий шаблон на основе типа данных, которые он собирается показать. Шаблон, определенный для типа Family, является иерархическим шаблоном, использующим свойство Members, чтобы показать членов его семейства.
Шаблон, определенный для типа FamilyMember, является обычным DataTemplate, так как этот тип не имеет дочерних элементов. Однако, если бы мы хотели чтобы каждый FamilyMember сохранял коллекцию своих детей, и возможно детей своих детей, то мы бы использовали вместо этого иерархический шаблон.
В обоих шаблонах мы используем изображение, которое представляет семью или члена семьи, а затем показываем некоторые данные о нем, такие как количество членов семьи или возраст человека.
В code-behind мы просто создаем два объекта класса Family, заполняем каждый из них набором членов, а затем добавляем эти объекты в список, который затем используется в качестве источника элементов для TreeView.
Итог
Используя привязку данных , TreeView очень легко настроить с возможностью указывать несколько шаблонов для рендеринга разных типов данных. Эти возможности практически безграничны.