-
TreeView控件:

TreeViews 数据绑定和多种模板

WPF TreeView 支持数据绑定(Data Binding),就像其他所有WPF控件一样,但是TreeView却能够天然的支持继承绑定。普通的DataTemplate通常不够高效。因此,我们使用继承数据模板(HierarchicalDataTemplate),它允许我们同时控制节点,以及该节点的子节点。

TreeView 基本数据绑定

在后面的例子中,我将演示使用分层数据模板(HierarchicalDataTemplate)是一件多么简单的工作。

  1. <Window x:Class="WpfTutorialSamples.TreeView_control.TreeViewDataBindingSample"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. xmlns:self="clr-namespace:WpfTutorialSamples.TreeView_control"
  5. Title="TreeViewDataBindingSample" Height="150" Width="200">
  6. <Grid Margin="10">
  7. <TreeView Name="trvMenu">
  8. <TreeView.ItemTemplate>
  9. <HierarchicalDataTemplate DataType="{x:Type self:MenuItem}" ItemsSource="{Binding Items}">
  10. <TextBlock Text="{Binding Title}" />
  11. </HierarchicalDataTemplate>
  12. </TreeView.ItemTemplate>
  13. </TreeView>
  14. </Grid>
  15. </Window>
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Windows;
  4. using System.IO;
  5. using System.Collections.ObjectModel;
  6. namespace WpfTutorialSamples.TreeView_control
  7. {
  8. public partial class TreeViewDataBindingSample : Window
  9. {
  10. public TreeViewDataBindingSample()
  11. {
  12. InitializeComponent();
  13. MenuItem root = new MenuItem() { Title = "Menu" };
  14. MenuItem childItem1 = new MenuItem() { Title = "Child item #1" };
  15. childItem1.Items.Add(new MenuItem() { Title = "Child item #1.1" });
  16. childItem1.Items.Add(new MenuItem() { Title = "Child item #1.2" });
  17. root.Items.Add(childItem1);
  18. root.Items.Add(new MenuItem() { Title = "Child item #2" });
  19. trvMenu.Items.Add(root);
  20. }
  21. }
  22. public class MenuItem
  23. {
  24. public MenuItem()
  25. {
  26. this.Items = new ObservableCollection<MenuItem>();
  27. }
  28. public string Title { get; set; }
  29. public ObservableCollection<MenuItem> Items { get; set; }
  30. }
  31. }

在XAML结构化文件中,可以看到TreeView的ItemTemplate具有一个HierarchicalDataTemplate。通过设置这个模板的ItemsSource属性,我指示它使用Items属性来查找子元素,并且我在内部定义了一个真正的模板,该模板只包含一个绑定到Title属性的TextBlock。

第一个例子非常简单,以至于我们只是手动添加了TreeView的元素,而不是生成一组对象并且绑定他们。但是,随着操作越来越复杂,使用数据绑定的优势会更加明显。

多个模板对于不同类型数据

下面这个例子,将增加一点复杂度,我想显示出一个家族树以及成员。一个家族使用一种方式来表现,而成员使用另一种方式来表现。为了完成以一点,我将创建两个模板,并且将他们作为资源指定给这棵树(或者这个窗口,或者这个程序,全都看你),然后令TreeView根据数据的类型选择正确的模板

以下是实现代码 - 随后将进行解释:

  1. <Window x:Class="WpfTutorialSamples.TreeView_control.TreeViewMultipleTemplatesSample"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. xmlns:self="clr-namespace:WpfTutorialSamples.TreeView_control"
  5. Title="TreeViewMultipleTemplatesSample" Height="200" Width="250">
  6. <Grid Margin="10">
  7. <TreeView Name="trvFamilies">
  8. <TreeView.Resources>
  9. <HierarchicalDataTemplate DataType="{x:Type self:Family}" ItemsSource="{Binding Members}">
  10. <StackPanel Orientation="Horizontal">
  11. <Image Source="/WpfTutorialSamples;component/Images/group.png" Margin="0,0,5,0" />
  12. <TextBlock Text="{Binding Name}" />
  13. <TextBlock Text=" [" Foreground="Blue" />
  14. <TextBlock Text="{Binding Members.Count}" Foreground="Blue" />
  15. <TextBlock Text="]" Foreground="Blue" />
  16. </StackPanel>
  17. </HierarchicalDataTemplate>
  18. <DataTemplate DataType="{x:Type self:FamilyMember}">
  19. <StackPanel Orientation="Horizontal">
  20. <Image Source="/WpfTutorialSamples;component/Images/user.png" Margin="0,0,5,0" />
  21. <TextBlock Text="{Binding Name}" />
  22. <TextBlock Text=" (" Foreground="Green" />
  23. <TextBlock Text="{Binding Age}" Foreground="Green" />
  24. <TextBlock Text=" years)" Foreground="Green" />
  25. </StackPanel>
  26. </DataTemplate>
  27. </TreeView.Resources>
  28. </TreeView>
  29. </Grid>
  30. </Window>
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Windows;
  4. using System.Collections.ObjectModel;
  5. namespace WpfTutorialSamples.TreeView_control
  6. {
  7. public partial class TreeViewMultipleTemplatesSample : Window
  8. {
  9. public TreeViewMultipleTemplatesSample()
  10. {
  11. InitializeComponent();
  12. List<Family> families = new List<Family>();
  13. Family family1 = new Family() { Name = "The Doe's" };
  14. family1.Members.Add(new FamilyMember() { Name = "John Doe", Age = 42 });
  15. family1.Members.Add(new FamilyMember() { Name = "Jane Doe", Age = 39 });
  16. family1.Members.Add(new FamilyMember() { Name = "Sammy Doe", Age = 13 });
  17. families.Add(family1);
  18. Family family2 = new Family() { Name = "The Moe's" };
  19. family2.Members.Add(new FamilyMember() { Name = "Mark Moe", Age = 31 });
  20. family2.Members.Add(new FamilyMember() { Name = "Norma Moe", Age = 28 });
  21. families.Add(family2);
  22. trvFamilies.ItemsSource = families;
  23. }
  24. }
  25. public class Family
  26. {
  27. public Family()
  28. {
  29. this.Members = new ObservableCollection<FamilyMember>();
  30. }
  31. public string Name { get; set; }
  32. public ObservableCollection<FamilyMember> Members { get; set; }
  33. }
  34. public class FamilyMember
  35. {
  36. public string Name { get; set; }
  37. public int Age { get; set; }
  38. }
  39. }

就像前面说到的,这两个模板被定义为TreeView的资源的一部分,并且允许TreeView根据不同的数据类型选择合适的模板进行展示。展示Family类型的模板被定义为分层模板(hierarchical template),并且使用Members属性显示家庭成员。

FamilyMember数据类型所使用的模板被定义为常规的数据模板(DataTemplate),因为这个类型没有任何子成员。但是,如果我们希望所有FamilyMember都有子成员,并且这些子成员还有子成员,那么就应该使用分层模板(hierarchical template)

在这两种模板中,我们都是用了一个图片表示了该节点是一个家庭还是家庭成员,并且展示了一些感兴趣的数据,比如家庭成员的数量,或者成员的年龄。

在后台代码中,我们只是简单的创建了两个Family的实例,并且使用一组家庭成员填充他们,然后将这些Family加入到一个列表,也就是TreeView的数据源。

小结

使用数据绑定,可以非常个性化TreeView,也可以使用多个模板表示不同的数据,表现可能性是无尽的。