This article has been localized into Chinese by the community.
TreeViews 数据绑定和多种模板
WPF TreeView 支持数据绑定(Data Binding),就像其他所有WPF控件一样,但是TreeView却能够天然的支持继承绑定。普通的DataTemplate通常不够高效。因此,我们使用继承数据模板(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结构化文件中,可以看到TreeView的ItemTemplate具有一个HierarchicalDataTemplate。通过设置这个模板的ItemsSource属性,我指示它使用Items属性来查找子元素,并且我在内部定义了一个真正的模板,该模板只包含一个绑定到Title属性的TextBlock。
第一个例子非常简单,以至于我们只是手动添加了TreeView的元素,而不是生成一组对象并且绑定他们。但是,随着操作越来越复杂,使用数据绑定的优势会更加明显。
多个模板对于不同类型数据
下面这个例子,将增加一点复杂度,我想显示出一个家族树以及成员。一个家族使用一种方式来表现,而成员使用另一种方式来表现。为了完成以一点,我将创建两个模板,并且将他们作为资源指定给这棵树(或者这个窗口,或者这个程序,全都看你),然后令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类型的模板被定义为分层模板(hierarchical template),并且使用Members属性显示家庭成员。
FamilyMember数据类型所使用的模板被定义为常规的数据模板(DataTemplate),因为这个类型没有任何子成员。但是,如果我们希望所有FamilyMember都有子成员,并且这些子成员还有子成员,那么就应该使用分层模板(hierarchical template)
在这两种模板中,我们都是用了一个图片表示了该节点是一个家庭还是家庭成员,并且展示了一些感兴趣的数据,比如家庭成员的数量,或者成员的年龄。
在后台代码中,我们只是简单的创建了两个Family的实例,并且使用一组家庭成员填充他们,然后将这些Family加入到一个列表,也就是TreeView的数据源。
小结
使用数据绑定,可以非常个性化TreeView,也可以使用多个模板表示不同的数据,表现可能性是无尽的。