如何为TreeView定义三层模板并实现数据绑定
一直以来都想对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定义三层模板并实现数据绑定的更多相关文章
- java导出Excel定义导出模板
在很多系统功能中都会有Excel导入导出功能,小编采用JXLS工具,简单.灵活. JXLS是基于 Jakarta POI API 的Excel报表生成工具,它采用标签的方式,类似于jsp页面的EL表达 ...
- Spring在bean配置文件中定义电子邮件模板
在上一篇Spring电子邮件教程,硬编码的所有电子邮件属性和消息的方法体中的内容,这是不实际的,应予以避免.应该考虑在Spring bean 配置文件中定义电子邮件模板. 1.Spring的邮件发件人 ...
- Vue基础系列(三)——Vue模板中的数据绑定语法
写在前面的话: 文章是个人学习过程中的总结,为方便以后回头在学习. 文章中会参考官方文档和其他的一些文章,示例均为亲自编写和实践,若有写的不对的地方欢迎大家和我一起交流. VUE基础系列目录 < ...
- SharePoint 2013 图文开发系列之定义站点模板
SharePoint站点模板是一个非常好的功能,方便我们开发一类网站,然后在此基础上做二次开发,对于SharePoint的使用,有着举足轻重的作用. 因为篇幅比较长,所以加上目录,方便大家查看: 一. ...
- ThinkPHP第三天(公共函数Common加载,dump定义,模板文件,定义替换__PUBLIC__)
1.公共函数定义 自动加载:在项目的common文件夹中定义,公共函数文件命名规则为common.php,只有命名成common.php才能被自动载入. 动态加载:可以修改配置项‘LOAD_EXT_F ...
- Vue 定义组件模板的七种方式(一般用单文件组件更好)
在 Vue 中定义一个组件模板,至少有七种不同的方式(或许还有其它我不知道的方式): 字符串 模板字面量 x-template 内联模板 render 函数 JSF 单文件组件 在这篇文章中,我将通过 ...
- Cocos2d-x 创建自己定义项目模板
你是否以前为cocos方便高速开发而兴奋,你是否以前为各种工具的便利开发而感动,但如今的你是否为每次创建一个新的项目都是HelloWorldScene而苦恼? 好吧,事实上我也感觉到了,每次创建一个项 ...
- RDLC后台自己定义报表模板
首先封装一个公共类,统一来操作RDLC报表 using System; using System.Collections.Generic; using System.Linq; using Syste ...
- idea-自定义Java模板文件
自定义 idea Java 模板步骤. #parse("File Header.java")表示引用的模板文件,如下:
随机推荐
- logbak 配置相关
一.配置简单 1. 配置简单,易于上手,通过logback.xml文件进行配置,如果没有配置的话,执行默认配置 <configuration> <appender name=&quo ...
- Matlab计算的FFT与通过Origin计算的FFT
实验的过程中,经常需要对所采集的数据进行频谱分析,软件的选择对计算速度影响挺大的.我在实验过程中,通常使用Origin7.5来进行快速傅里叶变换,因为方便快捷,计算之后,绘出来的图也容易编辑.但是当数 ...
- nodeJS之crypto模块公钥加密及解密
nodeJS之crypto模块公钥加密及解密 NodeJS有以下4个与公钥加密相关的类.1. Cipher: 用于加密数据:2. Decipher: 用于解密数据:3. Sign: 用于生成签名:4. ...
- PAT A1126 Eulerian Path (25 分)——连通图,入度
In graph theory, an Eulerian path is a path in a graph which visits every edge exactly once. Similar ...
- Selenium:集成测试报告
参考内容:虫师:<selenium2自动化测试实战——基于python语言> PS:书中的代码,只能做参考,最好还是自己码一码,不一定照搬就全是对的,实践出真知啊,踩了很多坑的说... 随 ...
- python descriptor 详解
descriptor简介 在python中,如果一个新式类定义了__get__, __set__, __delete__方法中的一个或者多个,那么称之为descriptor.descriptor有分为 ...
- I2S音频总线学习
IIS音频总线学习(一)数字音频技术 一.声音的基本概念 声音是通过一定介质传播的连续的波. 图1 声波 重要指标: 振幅:音量的大小 周期:重复出现的时间间隔 频率:指信号每秒钟变化的次数 声音按频 ...
- React-使用combineReducers完成对数据对拆分管理
数据都放在reducer.js下不利于对数据进行管理,可以把一个大的reducer.js拆分成多个小的reducer.js. 小的reducer.js const defaultState={ foc ...
- Ionic2 App Import BrowserAnimationsModule or NoopAnimationsModule问题
在开发app的过程中遇见了动画相关方面的问题,具体如下: 解决方法是:在app.module.ts模块中引入BrowserAnimationsModule import { BrowserAnimat ...
- 学习ML.NET(3): 导入数据集
机器学习算法需要作用于数据,用来训练算法模型.数据集通常是以纯文本文件存储的表格数据,文件的每一行是一条数据记录,每条记录由多列组成,列之间用分隔符(一般是逗号,)分开,例如前面用到过的鸢尾花数据集. ...