如何为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")表示引用的模板文件,如下:
随机推荐
- Linux系统学习之软件安装
一.源码包编译安装 由于计算机无法直接执行用高级语言编写的源程序,因此想要运行程序,就需要一种机制来让计算机识别,这样程序才可能运行起来.一般来说,计算机中存在解释型和编译型两种语言. 所谓解释型语言 ...
- yum问题解决
错误信息1:There was a problem importing one of the Python modulesrequired to run yum. The error leading ...
- 【Atcoder yahoo-procon2019-qual D】 Ears
Atcoder yahoo-procon2019-qual D 题意:给你\(L\)个耳朵(???),以及一条范围从\(0\)到\(L\)的数轴,你可以选择一个出发点,从该点开始随意走动,如果经过了\ ...
- 高显卡安装 低版本的ubuntu系统导致hdmi线不能用
- 苹果与Windows双系统时间不同步的解决办法
步骤:打开C盘>Windows>System32,找到cmd.exe,右键以管理员的身份运行. Reg add HKLM\SYSTEM\CurrentControlSet\Control\ ...
- SQLServer 窗口函数(转载)
一.窗口函数的作用 窗口函数是对一组值进行操作,不需要使用GROUP BY 子句对数据进行分组,还能够在同一行中同时返回基础行的列和聚合列.窗口函数,基础列和聚合列的查询都非常简单. 二.语法格式 窗 ...
- Luogu3877 TJOI2010 打扫房间 二分图、网络流
传送门 真是菜死了模板题都不会-- 首先\(30 \times 30\)并不能插头DP,但是范围仍然很小所以考虑网络流. 注意每个点都要包含在一个回路中,那么每一个点的度数都必须为\(2\),也就是说 ...
- flask-sqlalchemy组件
一.简介 flask本身没有内置orm框架,需要依赖第三方模块,这里介绍flask-sqlalchemy,而flask-sqlalchemy是一个flask的扩展,本质上是对sqlalchemy的进一 ...
- mysql中Error : Invalid default value for 'timestamp'问题
在执行mysql数据库时报错 timestamp给默认值出问题. 原因是:mysql的配置参数中sql_node中NO_ZERO_IN_DATE, NO_ZERO_DATE控制了times ...
- [Socket]Socket聊天小程序
一个简单是Socket聊天小程序,读写操作在不同的线程中.服务器端采用线程池. 1.Server import java.io.IOException; import java.net.ServerS ...