原文:潜移默化学会WPF(难点控件treeview)--改造TreeView(CheckBox多选择版本),递归绑定数据

目前自己对treeview的感慨很多

今天先讲 面对这种 表结构的数据 的其中一种绑定方法,后面多几列其他属性都没关系,例如多个字段,

1  A  0

2  B  0

3  C  0

4  D  1

5  E  2

6  F  4

7  G 1

...

就是递归型的表结构

然后通过treeview 展示( treeview 的name 叫 tv , collection 是 ObservableCollection<T> 的 一个实例)

1.首先你必须需要  要建立一个 跟treeview 结构很相似的一个集合,这里建议用  ObservableCollection<T>   这个集合很特殊,你要记得,例如 tv.ItemsSource = this.collection;  当你这样绑定时,修改collection的属性时就是修改treeview绑定的某些属性

2.在做绑定时一定要 搞清楚treeview的item的结构,你想呈现什么样的,每个 treeveiwItem就是一个对象 ,这个对象可以用一个类去替代,或者什么去替代

3. 不啰嗦了,说正题,新建一个实体类

例如

   /// <summary>
////// </summary>
public class ReportCategoryEntity
{
/// <summary>
/// ID
/// </summary>
public int Id { get; set; }
/// <summary>
/// 名称
/// </summary>
public string Title { get; set; }
/// <summary>
///父节点
/// </summary>
public int ParentID { get; set; } }

这个应该看得懂吧,加入那个递归表 叫 FoodCatagory(菜品目录) 表,现在只要递归显示出来就行了

把他所有行取出来 select * from FoodCatagory,如果其中不止基本的三列,有其他列,例如通过这些列的值  作为控制 treeview显示的样式的条件用 这也是很不错的点子,真的,比如说再加一个图片的地址,如果有个图片地址字典表,这里就存那个表中的字段了,如果其他字段你需要,那你可以继续写在 ReportCategoryEntity 这个类中

读出来的所有行封装到  List<ReportCategoryEntity>    lstReportCategoryEntity  ,这个应该会把,如果不会,说明你的oop基础没学好了

好了

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.Windows.Media; namespace 命名空间
{
public class TreeCategory : INotifyPropertyChanged
{
private ObservableCollection<TreeCategory> children = new ObservableCollection<TreeCategory>(); public TreeCategory() { } public TreeCategory(List<ReportCategoryEntity> totalCategory, int parentID) //0 根目录
{
//Parent = this;
foreach (ReportCategoryEntity item in totalCategory)
{
if (item.ParentID == parentID)
{
TreeCategory tc = new TreeCategory(totalCategory, item.Id);
tc.Title = item.Title;
children.Add(tc);
}
}
} public ObservableCollection<TreeCategory> Children
{
get { return this.children; }
} /// <summary>
/// 显示的名称
/// </summary>
private string title;
public string Title
{
get
{
return title;
}
set
{
title = value;
this.NotifyPropertyChanged("Title");
}
}
/// <summary>
/// 是否选中
/// </summary>
private bool isSelected = false;
public bool IsSelected
{
set
{
this.isSelected = value;
this.NotifyPropertyChanged("IsSelected");
}
get { return this.isSelected; }
} /// <summary>
/// 标题字体颜色
/// </summary>
private Brush foregroundBrush = new SolidColorBrush(Colors.Black);
public Brush ForegroundBrush
{
set
{
this.foregroundBrush = value;
this.NotifyPropertyChanged("ForegroundBrush");
}
get { return this.foregroundBrush; }
} public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
} }
}

接下来再建立一个最重要的 类,用来控制treeview显示的,看似像实体类,但又不像,下面是我建立的,本类下有个本类的集合的属性,还是ObservableCollection集合的,加了 INotifyPropertyChanged 只是为了达到只要修改这个集合的某些属性的值,就可以修改treeview的状态了。

例如我这里添加了 标题字体颜色  ForegroundBrush  这个属性,就是为了达到treeview的每个节点的显示颜色,你在递归的时候就可以根据 ReportCategoryEntity 的某些属性作为条件,然后动态给ForegroundBrush  赋值,要记住,每一个 TreeCategory 类就已经对应了一个 treeviewItem,该类的每一个字段都可以作为 treeview 显示出来的条件,至于前面treeview的样式模板该怎么写,很快你就清楚了

现在说一下 xaml 中前台的写法

 <TreeView Name="tv" Width="" Height="" MaxHeight="" BorderThickness="">
<TreeView.ItemContainerStyle>
<Style TargetType="TreeViewItem">
<Setter Property="TreeViewItem.IsExpanded" Value="True"/>
<!--<Setter Property="TreeViewItem.IsSelected" Value="{Binding IsSelected}"/>-->
<!--<EventSetter Event="MouseMove" Handler="tree_MouseMove" />-->
<!--<EventSetter Event="KeyDown" Handler="treeViewItem_KeyDown" />-->
<Setter Property="TreeViewItem.Margin" Value="0,1,0,0"/>
</Style>
</TreeView.ItemContainerStyle>
<TreeView.ItemTemplate>
<HierarchicalDataTemplate DataType="{x:Type c:TreeCategory}" ItemsSource="{Binding Children}">
<StackPanel Margin="-2,0,0,0" Orientation="Horizontal" x:Name="staTree">
<CheckBox Content="{Binding Title}" FontSize="" FontFamily="微软雅黑" Tag="{Binding Children}" IsChecked="{Binding IsSelected}" Foreground="{Binding ForegroundBrush}" Unchecked="ck_Unchecked" Checked="ck_Checked"></CheckBox>
</StackPanel>
<HierarchicalDataTemplate.Triggers>
<DataTrigger Binding="{Binding IsSelected}" Value="true">
<Setter TargetName="staTree" Property="Background" Value="White"/>
</DataTrigger>
</HierarchicalDataTemplate.Triggers>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate> </TreeView>

重点看  <TreeView.ItemTemplate>  这个节点下面的 ,<TreeView.ItemContainerStyle>用来控制总体显示样式的

现在你应该有点清楚了

1. 首先你要知道  treeviewItem 对应一个  TreeCategory ,treeview控件每个节点下都有可能有子节点,像一个集合,所以我在TreeCategory 类中又包括了他自己的一个集合,已达到构造出和treeview很像的一个结构,感觉到了吗

2. ReportCategoryEntity  这个实体是  把从数据库读出来的每条数据的一个net样子,一条表中的数据对应一个 ReportCategoryEntity  实体对象,达到封装效果,不一定只有这三个字段,拓展他以达到treeview显示更丰富的效果,而且treeview的模板很好写,可以改造出很多种

3.就是 TreeCategory 类  ,如果以前没有接触xaml语言的可能会有疑问

public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}

为什么会有这堆代码,而且每个属性后面,又调了这个 NotifyPropertyChanged 方法,我不知道原理,但我知道怎么用了,wpf的控件很奇特,不像winform控件或者 asp.net控件那么死,重写个控件很难,这就是为什么wpf 做的桌面软件五花八门,而且很炫,只要你的到控件,不脱离实际,控件都可以变成你想要的控件。又说了好多废话。

最重要的还是我的那个 递归

 public TreeCategory(List<ReportCategoryEntity> totalCategory, int parentID)  //0  根目录
{
//Parent = this;
foreach (ReportCategoryEntity item in totalCategory)
{
if (item.ParentID == parentID)
{
TreeCategory tc = new TreeCategory(totalCategory, item.Id);
//加一些你想要的字段,然后在这里赋值吧
tc.Title = item.Title;
children.Add(tc);
}
}
}

4.为了达到treeview显示的不同效果,加了数据触发器,这样后台一行代码也不要写,有必要的话,你可以再加一个值转换器吧 ,加一些你想要的数据触发器吧,丰富显示效果,例如根据某个字段作为判断条件,如果是什么,把image 控件的source地址换了,就可以达到不同的节点,显示不同的图片了  ,具体应用有很多

<HierarchicalDataTemplate.Triggers>
<DataTrigger Binding="{Binding IsSelected}" Value="true">
<Setter TargetName="staTree" Property="Background" Value="White"/>
</DataTrigger>
                    //加一些你想要的数据触发器吧,丰富显示效果,例如根据某个字段作为判断条件,如果是什么,把image 控件的source地址换了,就可以达到不同的节点,显示不同的图片了        
</HierarchicalDataTemplate.Triggers>

后台绑定

    private ObservableCollection<TreeCategory> collection = new ObservableCollection<TreeCategory>();

     this.collection = new TreeCategory(ctagr, ).Children;
treeCategories.ItemsSource = this.collection;
ctagr 是个List<ReportCategoryEntity> 集合

先冒个泡

这是我做的一个菜品目录checkbox多选版本的 ,作为导航栏的,例如选中这个目录,列出这个目录下的所有菜,或者计算出这个菜品目录的菜的销售情况等等,扩展一下,部门与员工是挺经典的一个例子

至于选中根节点,子节点全部选中,那你可以写在checkbox的事件里,应该会吧,这我就不写了,建议递归吧,应为你不知道他下面有多少个子节点

这个我加了checkbox选择的模式,全选,全不选,反选,随选

这个我就再说一点吧,然后来体现ObservableCollection 集合的好处

你不可能修改treeviewItem的属性吧,那个有点傻了

直接修改ObservableCollection 中的 TreeCategory 的IsSelected属性就行了,treeview中自动体现

这里我就只说个全选,全不选 的吧

下面是我写的一个算法

为了防止你粘贴复制,不思考我就上个图吧

反选应该就不用我说了吧,留着思考吧

而且每个 节点的 checkbox都是可以改的,而且你还可以组合控件,例如把很多控件放在stackpanel 中,作为一个treeviewItem

例如每个节点鼠标移上去的效果你都可以很轻松的改的,就看你的技术了,鼠标移上去,我就不说了

再看个图吧

如果你熟悉treeview的话,迅雷看看的这个目录效果很轻松的可以做出来,那个TreeviewItem加载动画也可以做

,这是个 目录下有具体内容的treeview结构,这个如果也用这种MVVM思想的话也可以很轻松的做出来,我做过,多态做的,呵呵,下次有时间的话就再写篇 treeview下面有内容时,该怎么写。

我自己感觉迅雷看看有点像 Expander 加 treeview  控件呢?下次做一个迅雷看看左边的目录 制作教程吧,好了,就暂时啰嗦到这里吧

潜移默化学会WPF(难点控件treeview)--改造TreeView(CheckBox多选择版本),递归绑定数据的更多相关文章

  1. WPF常用控件应用demo

    WPF常用控件应用demo 一.Demo 1.Demo截图如下: 2.demo实现过程 总体布局:因放大缩小窗体,控件很根据空间是否足够改变布局,故用WrapPanel布局. <ScrollVi ...

  2. 潜移默化学会WPF(绚丽篇)--热烈欢迎RadioButton,改造成功,改造成ImageButton,新版导航

    原文:潜移默化学会WPF(绚丽篇)--热烈欢迎RadioButton,改造成功,改造成ImageButton,新版导航 本样式 含有  触发器 和 动画    模板  ,多条件触发器,还有布局 本人博 ...

  3. WPF Popup 控件导致被遮挡内容不刷新的原因

    WPF Popup 控件导致被遮挡内容不刷新的原因 周银辉 今天在写一个WPF控件时用到了Popup控件,很郁闷的情况是:当popup关闭时,原来被popup挡住的界面部分不刷新,非要手动刷新一下(比 ...

  4. 创建 WPF 工具箱控件

    创建 WPF 工具箱控件 WPF (Windows Presentation Framework) 工具箱控件模板允许您创建 WPF 控件,会自动添加到 工具箱 安装扩展的安装. 本主题演示如何使用模 ...

  5. wpf打印控件 实现分页打印控件功能

    因为 要实现打印 wpf  listbox控件  数据特别多 要打印在 几张纸上    找了几天 都没有找到相关的例子 现在 解决了 在这里和大家分享一下 public void print(Fram ...

  6. WPF 分页控件 WPF 多线程 BackgroundWorker

    WPF 分页控件 WPF 多线程 BackgroundWorker 大家好,好久没有发表一篇像样的博客了,最近的开发实在头疼,很多东西无从下口,需求没完没了,更要命的是公司的开发从来不走正规流程啊, ...

  7. WPF Image控件中的ImageSource与Bitmap的互相转换

    原文:WPF Image控件中的ImageSource与Bitmap的互相转换  1.从bitmap转换成ImageSource [DllImport("gdi32.dll", ...

  8. 【转】WPF - 第三方控件

    WPF - 第三方控件 目前第三方控件在网上形成巨大的共享资源,其中包括收费的也有免费的,有开源的也有不开源的,合理的使用第三方控件将使项目组的工作事半功倍.比如项目中有些复杂的业务逻辑.有些绚丽的效 ...

  9. WPF布局控件与子控件的HorizontalAlignment/VerticalAlignment属性之间的关系

    WPF布局控件与子控件的HorizontalAlignment/VerticalAlignment属性之间的关系: 1.Canvas/WrapPanel控件: 其子控件的HorizontalAlign ...

随机推荐

  1. angular自定义管道

    原文地址 https://www.jianshu.com/p/5140a91959ca 对自定义管道的认识 管道的定义中体现了几个关键点: 1.管道是一个带有“管道元数据(pipe metadata) ...

  2. ng-cli搭建angular项目框架

    原文地址 https://www.jianshu.com/p/0a8f4b0f29b3 环境准备 以下步骤都不需要事先创建文件夹,只是环境的准备过程,只有到需要搭建项目的时候才需要创建文件夹用来存放项 ...

  3. python 升级pip

    废话少说,直接上图,希望谅解我的懒惰!:)

  4. Android面试准备 第二天 第五例 数据存储

    參考:http://blog.csdn.net/lmj623565791/article/details/24015867 5.Activity用SharedPreferences保存数据,大小有木有 ...

  5. URIEncoding

    http://thoughtfly.iteye.com/blog/1533481 http://docs.spring.io/spring/docs/current/spring-framework- ...

  6. js获取浏览器尺寸

    Javascript: alert(document.body.clientWidth);        //网页可见区域宽(body) alert(document.body.clientHeigh ...

  7. AngularJS之ng-class指令

    ng-class是AngularJS预设的一个指令,用于动态自定义dom元素的css class name. 在angular中为我们提供了3种方案处理class: 1:scope变量绑定. < ...

  8. 【u005】封锁阳光大学

    Time Limit: 1 second Memory Limit: 128 MB [问题描述] 曹是一只爱刷街的老曹,暑假期间,他每天都欢快地在阳光大学的校园里刷街.河蟹看到欢快的曹,感到不爽.河蟹 ...

  9. 手把手教你完成App支付JAVA后台-支付宝支付JAVA

    接着上一篇博客,我们暂时完成了手机端的部分支付代码,接下来,我们继续写后台的代码. 后台基本需要到以下几个参数,我都将他们写在了properties文件中: 支付宝参数 AliPay.payURL = ...

  10. [React] Break up components into smaller pieces using Functional Components

    We are going to ensure our app is structured in a clear way using functional components. Then, we ar ...