[Silverlight]HierarchicalDataTemplate层次数据

 在开发中,经常会以层次结构来组织数据,最典型的例子莫过于树视图。本文讲述Silverlight中的层次数据的递归绑定,采用TreeView作为示例控件。

 在本文中,以“学校——学院——专业”作为数据层次示例,由此构建一下类型:

 

代码
    public class School
{
  
public string SchoolName { get; set; }

  
public ObservableCollection<Academy> Academys { get; set; }
 }

 
public class Academy
 {
  
public string AcademyName { get; set; }

  
public ObservableCollection<Subject> Subjects { get; set; }
 }

 
public class Subject
  {
  
public string SubjectName { get; set; }
 }

现在希望在一个ItemsControl控件中,以层次的方式显示这些数据,正如之前所说,使用TreeView控件,毕竟它是最典型的层次数据控件。目标是只使用一句数据绑定代码,就能进行完整的树结构数据绑定,实现以下效果:

首先,定义这些数据类型,包括学校,学院,专业课程,代码如下:

代码
   public class School
{
public string SchoolName { get; set; }

public ObservableCollection<Academy> Academys { get; set; }
}

public class Academy
{
public string AcademyName { get; set; }

public ObservableCollection<Subject> Subjects { get; set; }
}

public class Subject
{
public string SubjectName { get; set; }
}

 其次,要有数据源,因为这是演示文章,所以不使用数据库那些复杂的数据源,而使用编程生成的数据源,代码如下:

代码
   public static class Data
{
public static ObservableCollection<School> SchoolData
{
get
{
ObservableCollection
<School> result = new ObservableCollection<School>();
School school
= null;
Academy academy
= null;
Subject subject
= null;

school
= new School() { SchoolName = "广东工业大学", Academys = new ObservableCollection<Academy>() };
result.Add(school);

academy
= new Academy() { AcademyName = "计算机学院", Subjects = new ObservableCollection<Subject>() };
school.Academys.Add(academy);

subject
= new Subject() { SubjectName = "计算机科学与技术" };
academy.Subjects.Add(subject);

subject
= new Subject() { SubjectName = "网络工程" };
academy.Subjects.Add(subject);

subject
= new Subject() { SubjectName = "软件工程" };
academy.Subjects.Add(subject);

academy
= new Academy() { AcademyName = "机电工程学院", Subjects = new ObservableCollection<Subject>() };
school.Academys.Add(academy);

subject
= new Subject() { SubjectName = "机械设计制造及其自动化" };
academy.Subjects.Add(subject);

subject
= new Subject() { SubjectName = "车辆工程" };
academy.Subjects.Add(subject);

subject
= new Subject() { SubjectName = "包装工程" };
academy.Subjects.Add(subject);

subject
= new Subject() { SubjectName = "工业工程" };
academy.Subjects.Add(subject);

subject
= new Subject() { SubjectName = "机械工程" };
academy.Subjects.Add(subject);

academy
= new Academy() { AcademyName = "轻工化工学院", Subjects = new ObservableCollection<Subject>() };
school.Academys.Add(academy);

subject
= new Subject() { SubjectName = "食品科学与工程" };
academy.Subjects.Add(subject);

subject
= new Subject() { SubjectName = "生物工程" };
academy.Subjects.Add(subject);

subject
= new Subject() { SubjectName = "应用化学" };
academy.Subjects.Add(subject);

subject
= new Subject() { SubjectName = "制药工程" };
academy.Subjects.Add(subject);

return result;
}
}
}

   

  上述代码中,构造了一个层次结构的数据源集合。通过SchoolData属性获取。

  接下来,就是XAML中定义TreeView以及层级数据模板HierarchicalDataTemplate,也就是这个功能的核心部分,代码如下:

  XAML:

代码
<UserControl xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
        x:Class="SilverlightApplication4.MainPage"
xmlns
="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:common
="clr-namespace:System.Windows;assembly=System.Windows.Controls"
xmlns:d
="http://schemas.microsoft.com/expression/blend/2008"

 Loaded
="UserControl_Loaded">
<UserControl.Resources>
<common:HierarchicalDataTemplate x:Key="subjectDataTemplate">
<TextBlock Text="{Binding SubjectName}" FontSize="14" />
</common:HierarchicalDataTemplate>

<common:HierarchicalDataTemplate x:Key="academyDataTemplate"
ItemsSource
="{Binding Subjects}"
ItemTemplate
="{StaticResource subjectDataTemplate}">
<TextBlock Text="{Binding AcademyName}" FontSize="16" />
</common:HierarchicalDataTemplate>

<common:HierarchicalDataTemplate x:Key="schoolDataTemplate"
ItemsSource
="{Binding Academys}"
ItemTemplate
="{StaticResource academyDataTemplate}">
<TextBlock Text="{Binding SchoolName}" FontSize="18" />
</common:HierarchicalDataTemplate>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="White">
<controls:TreeView x:Name="testInstance"
ItemTemplate
="{StaticResource schoolDataTemplate}">
</controls:TreeView>
</Grid>
</UserControl>


  第一部分的高亮代码,是使用HierarchicalDataTemplate控件所需要的命名空间引用。

  第二部分的高亮代码,定义了三个HierarchicalDataTemplate数据模板控件,定义在UserControl的资源中。(说明了这个数据模板可以定义在多种位置上。只要TreeView能引用就可以)。从上到下,第一个定义的是subjectDataTemplate,这个数据模板用于呈现专业课程数据项。第二个定义的是academyDataTemplate,同样,这个数据模板定义的是用于呈现学院数据项的,但不一样的是:

    1.这个数据模板还定义了ItemsSource与ItemTemplate。它们的意义分别如下:

      a. ItemsSource={Binding Subjects}

        此代码的功能就是:在这个呈现学院数据的数据模板中,假如数据源(代表

        学院的数据对象)存在一个Subjects属性,就把该属性返回的数据绑定到学

        院数据项的所有子项当中。而之前定义的Academy类型中,的确存在Subject

        s属性,因此该属性返回的所有专业课程对象,都会绑定到学院数据项的所有

        子项中。

      b. ItemTemplate={StaticResource subjectDataTemplate}

        此代码的功能就是:学院数据项的子项使用什么数据模板来呈现子项数据,

        这样就很容易理解为什么使用资源中的subjectDataTemplate数据模板,因为

        该模板就是为了呈现专业课程数据而定义的。(也正因如此,所以subjectDat

        aTemplate的定义必须在academyDataTemplate的定义之后,否则不能通过

        XAML中的语法进行资源引用)

 接下来的schoolDataTemplate定义实现的是同样的含义,请读者自己分析一下,加深理解。综上,可以看到,实现层次结构数据的连锁绑定,关键就在于HierarchicalDataTemplate的ItemsSource及ItemTemplate属性定义。

 第三部分的高亮代码,定义了一个TreeView控件。该控件的ItemTemplate使用了schoolDataTemplate,也就是说,TreeView以及其他ItemsControl控件,在它们的子项数据模板中,只需要应用顶层的HierarchicalDataTemplate数据模板,而往后各个子层的数据模板是怎样,数据源绑定什么属性,都由各层的HierarchicalDataTemplate定义决定。

 接下来就是对TreeView进行数据绑定的程序代码了。我把这个绑定过程写在UserControl的Loaded事件中,当然可以写在别的地方。代码如下:

private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
 testInstance.ItemsSource
= Data.SchoolData;
}

  

 就是这样简单的数据绑定代码,就解决对一整个层次结构的数据显示问题。由于我们使用的都是ObservableCollection<T>,因此对集合的任何修改都会马上更新到TreeView中。来到这里已经解决了各层数据异构的绑定问题。那如果各层数据是同构的怎样呢?(异构的意思指每层的数据对象是不一样的,例如之前例子的School——Academy——Subject,同构的例子有文件目录数据)。

 同样首先是数据对象的定义,代码如下:

public class FileInfo
{
public string FileName { get; set; }

public ObservableCollection<FileInfo> ChildFiles { get; set; }
}

 构造数据源的代码如下:

代码
  public static class FileData
{
public static ObservableCollection<FileInfo> FileCatalog
{
get
{
ObservableCollection
<FileInfo> result = new ObservableCollection<FileInfo>();

FileInfo root
= new FileInfo() { FileName = "RootFile", ChildFiles = new ObservableCollection<FileInfo>() };
result.Add(root);

FileInfo file_i
= null;
FileInfo file_j
= null;
FileInfo file_k
= null;

for (int i = 0; i < 3; i++)
{
file_i
= new FileInfo() { FileName = "File_" + i, ChildFiles = new ObservableCollection<FileInfo>() };

root.ChildFiles.Add(file_i);

for (int j = 0; j < 5; j++)
{
file_j
= new FileInfo() { FileName = file_i.FileName + "_" + j, ChildFiles = new ObservableCollection<FileInfo>() };

file_i.ChildFiles.Add(file_j);

for (int k = 0; k < 4; k++)
{
file_k
= new FileInfo() { FileName = file_j.FileName + "_" + k, ChildFiles = new ObservableCollection<FileInfo>() };

file_j.ChildFiles.Add(file_k);
}
}
}

return result;
}
}
}

 顶层数据项的HierarchicalDataTemplate数据模板定义为:

代码
<common:HierarchicalDataTemplate x:Key="fileDataTemplate"
ItemsSource
="{Binding ChildFiles}">
<TextBlock Text="{Binding FileName}" FontSize="15" />
</common:HierarchicalDataTemplate>

 修改一下TreeView,使用这个数据模板,就可以实现递归数据绑定。这样,每一层的数据呈现都使用相同的数据模板。也就是说,当前HierarchicalDataTemplate不指定下一层子项的ItemTemplate时,就会递归使用自身作为子项数据模板。运行结果如下:

posted @ 2010-05-09 21:01  DOF_KL  阅读(2682)  评论(1编辑  收藏  举报