[Silverlight]HierarchicalDataTemplate层次数据

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

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

 

ContractedBlock.gif ExpandedBlockStart.gif 代码
    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控件,毕竟它是最典型的层次数据控件。目标是只使用一句数据绑定代码,就能进行完整的树结构数据绑定,实现以下效果:

2010041819211110.jpg

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

ContractedBlock.gif ExpandedBlockStart.gif 代码
   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 ; }
}

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

ContractedBlock.gif ExpandedBlockStart.gif 代码
   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:

ContractedBlock.gif ExpandedBlockStart.gif 代码
< 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 ; }
}

 构造数据源的代码如下:

ContractedBlock.gif ExpandedBlockStart.gif 代码
  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数据模板定义为:

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

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

2010041819221468.jpg

转载于:https://www.cnblogs.com/klzwj1988/archive/2010/05/09/1731311.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值