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,也可以使用多个模板表示不同的数据,表现可能性是无尽的。