如何为TreeView定义三层模板并实现数据绑定

时间:2023-01-27 13:50:35

一直以来都想对TreeView定义多层模板,并实现数据绑定做一个总结,今天在这里做一个概述,我们常用的两层的TreeView绑定的话,我们首先修改TreeView的模板,这里我们使用的是级联的数据模板,又称之为分层数据模板,这里包含几个重要的属性意义:

DataType指定模板用于哪种数据类型

ItemsSource指定该类数据的子集,即下一层显示那些数据

内容 指定数据如何显示 绑定哪个属性

在我们的例子中第一层模板使用的数据类型是local命名空间下的PlayList类,ItemsSource指定该类数据的子集,即下一层显示那些数据,在这里指的是HierarchicalData Template.ItemTemplate 中的TextBlock使用的数据源类型。此处我们还定义了另外一个类 PlayListItem用来显示第二层数据,即子集显示的类型。这里的Item是我们定义的一个 ObservableCollection<PlayListItem> Item ,有了这个集合我们就能够获取到第二层的数据源,这个是非常重要的。这个集合提供了Add和Remove以及Clear等方法,由于该类实现了INotifyPropertyChanged接口,所以在删除项、增加项或者移除项的时候,会通知UI同步更新数据源,这个是非常重要的,在定义完模板之后,我们就需要将相应的数据添加到数据源中,在主程序中我们将所有的PlayList添加到一个ObservableCollection<PlayList> Root 中,最后我们通过 this.treeView.ItemsSource=Root来实现数据的绑定,至于怎么获取数据源,这个我们可以是获取多级文件夹分别绑定到该类的某一个属性上,或者是从数据库中获取数据然后再添加到数据源中来实现数据的绑定。

<TreeView.ItemTemplate >
  <HierarchicalDataTemplate DataType="{x:Type local:PlayList}" ItemsSource="{Binding Path=Item}">
    <Border BorderBrush="Silver" CornerRadius="3" BorderThickness="0" Margin="3" Name="fathernod" Width="250" ContextMenu="{StaticResource   sampleContextMenu1}" MouseRightButtonUp="OnMouseRightButtonUp" >
      <TextBlock Name="PlayListTextBlock" Text="{Binding Path=GetListName, Mode=TwoWay}" Foreground="White" Margin="0" FontStyle="Normal"  FontWeight="Bold">
      </TextBlock>
    </Border>
  <HierarchicalDataTemplate.ItemTemplate >
    <DataTemplate>
     <TextBlock Name="myChildnode" Text="{Binding Path=ResourceName,Mode=OneWay}" Foreground="White" FontSize="18"  Margin="-3,2,0,0">

</TextBlock>
    </DataTemplate>
  </HierarchicalDataTemplate.ItemTemplate>
 </HierarchicalDataTemplate>
</TreeView.ItemTemplate>

下面再分别贴出两个类的具体代码,仅供参考:

PlayList.cs

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
using System.ComponentModel;

using System.Windows.Controls;

namespace EarthSimulation
{
  public class PlayList:INotifyPropertyChanged
  {
    public event PropertyChangedEventHandler PropertyChanged;
  public PlayList(String name)
  {

    this.ListName = name;
  }
public String ListName;
//ObservableCollection<T>表示一个动态数据集合,在添加项、移除项或刷新整个列表时,此集合将提供通知。
private ObservableCollection<PlayListItem> _item = new ObservableCollection<PlayListItem>();
public ObservableCollection<PlayListItem> Item
{
  private set{}
  get
  {
    return _item;
  }
}
public void AddItem( PlayListItem item1)
{
  _item.Add(item1);
}
public void RemoveItem(PlayListItem olditem)
{
  _item.Remove(olditem);
}
public string GetListName
{
get
{
  return ListName;
}
set
{
  ListName = value;
  if (this.PropertyChanged != null)//激发事件,参数为ListName属性
  {
    this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs("GetListName"));
  }
}

}

}

}

PlayListItem.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace EarthSimulation
{
public class PlayListItem
{
public PlayListItem(PlayList list,int indexTemp)
{
  this.List = list;
  this.parentIndex=indexTemp;
}
//获取资源的名称
private string resourcename;
public string ResourceName
{
set
{
  resourcename=value;
}
get
{
  return resourcename;
}
}
//存储资源的路径
public String DirectoryArray{ set;get; }
public PlayList List { set; get; }
public int parentIndex { set; get; }
}
}

以上是通过分层模板来定义两层数据,下面介绍如何定义三层数据的数据模板,这里可以参考MSDN上的一个例子:来进行定义,这里是仿照该例子来定义的三层数据模板,这里我们将该模板定义为资源,

<Grid.Resources>

<HierarchicalDataTemplate DataType="{x:Type local:PoliceCarRoot}" ItemsSource="{Binding Path=Headers}" >
  <Border BorderBrush="Silver" CornerRadius="3" BorderThickness="0" Margin="3" Name="fathernod" Width="250" >
    <StackPanel Orientation="Horizontal" MouseLeftButtonDown="PoliceCarTreeView_MouseLeftButtonDown" >
      <CheckBox VerticalAlignment="Center" IsChecked="{Binding IsChecked, Mode=TwoWay}"/>
      <TextBlock Name="GroupTextBlock" Text="{Binding Path=CompanyName, Mode=TwoWay}" Foreground="Black"
        Margin="1,0,0,0" FontStyle="Normal" FontWeight="Bold" Width="150">
      </TextBlock>
    </StackPanel>
  </Border>
</HierarchicalDataTemplate>

<HierarchicalDataTemplate DataType="{x:Type local:PoliceCarGroup}" ItemsSource="{Binding Path=Item}">
  <Border BorderBrush="Silver" CornerRadius="3" BorderThickness="0" Margin="3" Name="fathernod" Width="250" >
    <StackPanel Orientation="Horizontal">
      <CheckBox VerticalAlignment="Center" IsChecked="{Binding IsChecked, Mode=TwoWay}" />
      <TextBlock Name="PoliceCarTextBlock" Text="{Binding Path=GroupName, Mode=TwoWay}" Foreground="Black" Margin="1,0,0,0"       FontStyle="Normal" FontWeight="Bold">
      </TextBlock>
    </StackPanel>
  </Border>
</HierarchicalDataTemplate>

<DataTemplate DataType="{x:Type local:PoliceCarInfo}" >
  <Border BorderBrush="Silver" CornerRadius="3" BorderThickness="0" Margin="3" Name="fathernod" Width="250" >
    <StackPanel Orientation="Horizontal">
      <CheckBox VerticalAlignment="Center" IsChecked="{Binding IsChecked, Mode=TwoWay}" />
      <TextBlock Name="PoliceCarTextBlock" Text="{Binding Path=CarNo, Mode=TwoWay}" Foreground="Black" Margin="1,0,0,0"           FontStyle="Normal" FontWeight="Bold">
      </TextBlock>
    </StackPanel>
  </Border>
</DataTemplate>

</Grid.Resources>

<TreeView x:Name="AllPoliceCarListView" Grid.Column="2" HorizontalAlignment="Left" Height="281" Margin="7,17,0,0" Grid.Row="1"                                   VerticalAlignment="Top" Width="321" Grid.ColumnSpan="2" PreviewMouseRightButtonUp="AllPoliceCarListView_PreviewMouseRightButtonUp"                     ContextMenu="{StaticResource sampleContextMenu3}"/>

在TreeView中我们不需要进行相关的模板进行修改,但是在绑定数据源的时候,我们需要将分层的数据绑定到该TreeView中,this.AllPoliceCarListView.ItemsSource = Root,其中Root中是我们添加的三层数据,这样当我们绑定数据源之后,会自动引用我们在资源中定义的三层数据模板,从而为TreeView填充数据,这种情况我们在使用的时候需要特别注意,对于具体怎么定义这些类,如何实现INotifyPropertyChange接口,这个同两层的数据模板绑定时类似,具体参考上面的代码;

总结:如果想定义更多层的数据,只需继续添加分层模板即可,但是也是只能够在资源中进行定义,不能在TreeView.ItemTemplate中定义。另外下面介绍一个加减号的ToggleButton,以及一个比较使用的TreeView样式,具体如下:

<Style x:Key="ExpandCollapseToggleStyle" TargetType="ToggleButton">
<Setter Property="Focusable" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
  <Grid Width="15" Height="13" SnapsToDevicePixels="True">
  <!-- Rectangle 9x9 pixels -->
  <Rectangle Width="15" Height="15" Stroke="#919191" SnapsToDevicePixels="true">
    <Rectangle.Fill>
      <LinearGradientBrush EndPoint="0.5,2" StartPoint="0.5,0">
        <GradientStop Color="White" Offset="0"/>
        <GradientStop Color="Silver" Offset="0.5"/>
        <GradientStop Color="LightGray" Offset="1"/>
      </LinearGradientBrush>
    </Rectangle.Fill>
</Rectangle>
<!-- 画一个垂直方向的直线 -->
<Rectangle x:Name="ExpandPath" Width="2" Height="8" Stroke="Black" SnapsToDevicePixels="true"/>
<!-- 画一个水平方向的直线 -->
<Rectangle Width="8" Height="2" Stroke="Black" SnapsToDevicePixels="true"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
  <Setter Property="Visibility" TargetName="ExpandPath" Value="Collapsed"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="Background" Value="Transparent"/>
<!--此处设置TreeViewItem的绑定样式-->
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}"></Setter>
<Setter Property="HorizontalContentAlignment" Value="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
<Setter Property="VerticalContentAlignment" Value="{Binding VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
<Setter Property="Padding" Value="1,0,0,0"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="FocusVisualStyle" Value="{StaticResource TreeViewItemFocusVisual}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TreeViewItem}">
<Grid>
<Grid.ColumnDefinitions>
  <ColumnDefinition MinWidth="19" Width="Auto"/>
  <ColumnDefinition Width="150" MinWidth="150"/>
  <ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
  <RowDefinition Height="Auto" MinHeight="22"/>
  <RowDefinition />
</Grid.RowDefinitions>
<!-- Connecting Lines -->
<!-- Horizontal line -->
<Rectangle x:Name="HorLn" Margin="9,1,0,0" Height="1" Stroke="Gray" SnapsToDevicePixels="True"/>
<!-- Vertical line -->
<Rectangle x:Name="VerLn" Width="1" Stroke="Gray" Margin="0,0,1,0" Grid.RowSpan="2" SnapsToDevicePixels="true" Fill="White"/>
<ToggleButton x:Name="Expander" Grid.Column="0" Grid.Row="0" ClickMode="Press" IsChecked="{Binding IsExpanded, RelativeSource={RelativeSource TemplatedParent}}" Style="{StaticResource ExpandCollapseToggleStyle}"/>
<Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Grid.Column="1" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
<ContentPresenter x:Name="PART_Header" ContentSource="Header" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" Width="250"/>
</Border>
<ItemsPresenter x:Name="ItemsHost" Grid.ColumnSpan="2" Grid.Column="1" Grid.Row="1" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsExpanded" Value="false">
<Setter Property="Visibility" TargetName="ItemsHost" Value="Collapsed"/>
</Trigger>
<Trigger Property="HasItems" Value="false">
<Setter Property="Visibility" TargetName="Expander" Value="Hidden"/>
</Trigger>
<Trigger Property="IsSelected" Value="true">
<Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/>
</Trigger>
<!--<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="true"/>
<Condition Property="IsSelectionActive" Value="false"/>
</MultiTrigger.Conditions>
<Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
</MultiTrigger>-->
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="VirtualizingStackPanel.IsVirtualizing" Value="true">
  <Setter Property="ItemsPanel">
  <Setter.Value>
  <ItemsPanelTemplate>
     <VirtualizingStackPanel/>
  </ItemsPanelTemplate>
  </Setter.Value>
  </Setter>
</Trigger>
</Style.Triggers>
</Style>

如何为TreeView定义三层模板并实现数据绑定的更多相关文章

  1. java导出Excel定义导出模板

    在很多系统功能中都会有Excel导入导出功能,小编采用JXLS工具,简单.灵活. JXLS是基于 Jakarta POI API 的Excel报表生成工具,它采用标签的方式,类似于jsp页面的EL表达 ...

  2. Spring在bean配置文件中定义电子邮件模板

    在上一篇Spring电子邮件教程,硬编码的所有电子邮件属性和消息的方法体中的内容,这是不实际的,应予以避免.应该考虑在Spring bean 配置文件中定义电子邮件模板. 1.Spring的邮件发件人 ...

  3. Vue基础系列(三)——Vue模板中的数据绑定语法

    写在前面的话: 文章是个人学习过程中的总结,为方便以后回头在学习. 文章中会参考官方文档和其他的一些文章,示例均为亲自编写和实践,若有写的不对的地方欢迎大家和我一起交流. VUE基础系列目录 < ...

  4. SharePoint 2013 图文开发系列之定义站点模板

    SharePoint站点模板是一个非常好的功能,方便我们开发一类网站,然后在此基础上做二次开发,对于SharePoint的使用,有着举足轻重的作用. 因为篇幅比较长,所以加上目录,方便大家查看: 一. ...

  5. ThinkPHP第三天&lpar;公共函数Common加载,dump定义,模板文件,定义替换&lowbar;&lowbar;PUBLIC&lowbar;&lowbar;&rpar;

    1.公共函数定义 自动加载:在项目的common文件夹中定义,公共函数文件命名规则为common.php,只有命名成common.php才能被自动载入. 动态加载:可以修改配置项‘LOAD_EXT_F ...

  6. Vue 定义组件模板的七种方式&lpar;一般用单文件组件更好&rpar;

    在 Vue 中定义一个组件模板,至少有七种不同的方式(或许还有其它我不知道的方式): 字符串 模板字面量 x-template 内联模板 render 函数 JSF 单文件组件 在这篇文章中,我将通过 ...

  7. Cocos2d-x 创建自己定义项目模板

    你是否以前为cocos方便高速开发而兴奋,你是否以前为各种工具的便利开发而感动,但如今的你是否为每次创建一个新的项目都是HelloWorldScene而苦恼? 好吧,事实上我也感觉到了,每次创建一个项 ...

  8. RDLC后台自己定义报表模板

    首先封装一个公共类,统一来操作RDLC报表 using System; using System.Collections.Generic; using System.Linq; using Syste ...

  9. idea-自定义Java模板文件

    自定义 idea Java 模板步骤. #parse("File Header.java")表示引用的模板文件,如下:

随机推荐

  1. POJ 1473 There&&num;39&semi;s Treasure Everywhere&excl;

    题目链接 小小的模拟一下. #include <cstdio> #include <cstring> #include <string> #include < ...

  2. iOS录音加播放&period;

    现在发现的事实有: 如果没有蓝牙设备, 那么可以用下面的方法边录音, 边放音乐: 在录音按钮按下的时候: _avSession = [AVAudioSession sharedInstance];   ...

  3. AspNet WebApi &colon; MessageHandler&lpar;消息处理器 &rpar;

    1. Http Message Handler WebApi中的MessageHandler类似MVC中的filter,可用于请求/响应到达真正目标前对请求或者响应进行修改,比如:用户身份验证,请求头 ...

  4. 为什么使用Hystrix?

    分布式服务弹性框架“Hystrix”实践与源码研究(一)   文章初衷 为了应对将来在线(特别是无线端)业务量的成倍增长,后端服务的分布式化程度需要不断提高,对于服务的延迟和容错管理将面临更大挑战,公 ...

  5. eclipse中hibernate和mybatis中xml配置文件的没有标签提醒解决方法

    当我们使用eclipse编写Mybatis或hibernate的xml文件时,面对众多标签的配置文件,却没有自动提醒,对于工作和学习都十分不方便. 之所以没有自动提醒,是因为dtd文件没有加载成功. ...

  6. MySQL数据类型--与MySQL零距离接触2-12主键约束

    定义一个主键,可以用PRIMARY KEY,也可以用KEY. 主键约束的字段禁止为空. 写入4条记录,查看它的自动编号: 自动编号确实是1 2 3 4 AUTO_INCREMENT字段必须定义为主键, ...

  7. Redis源码阅读(六)集群-故障迁移&lpar;下&rpar;

    Redis源码阅读(六)集群-故障迁移(下) 最近私人的事情比较多,没有抽出时间来整理博客.书接上文,上一篇里总结了Redis故障迁移的几个关键点,以及Redis中故障检测的实现.本篇主要介绍集群检测 ...

  8. Reinvent the Wheel Often

    Reinvent the Wheel Often Jason P. Sage Just use something that exists-it's silly to reinvent the whe ...

  9. div布局方案整理

    实际项目开发过程中遇到页面 DIV 左右布局的需求:左侧 DIV 固定宽度,右侧 DIV 自适应宽度,填充满剩余页面,由此引申出本文的几种解决方案 1 左侧 DIV 设置 float 属性为 left ...

  10. 轻量集群管理工具PSSH

    PSSH 的意思是 Parallel SSH,并行的SSH,很好理解,PSSH 可以让一条命令在多个服务器上同时执行 这就简化了集群的管理工作,例如想查看一下各台服务器现在的负载状况,就可以通过 PS ...