潜移默化学会WPF(难点控件treeview)--改造TreeView(CheckBox多选择版本),递归绑定数据
原文:潜移默化学会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多选择版本),递归绑定数据的更多相关文章
- WPF常用控件应用demo
WPF常用控件应用demo 一.Demo 1.Demo截图如下: 2.demo实现过程 总体布局:因放大缩小窗体,控件很根据空间是否足够改变布局,故用WrapPanel布局. <ScrollVi ...
- 潜移默化学会WPF(绚丽篇)--热烈欢迎RadioButton,改造成功,改造成ImageButton,新版导航
原文:潜移默化学会WPF(绚丽篇)--热烈欢迎RadioButton,改造成功,改造成ImageButton,新版导航 本样式 含有 触发器 和 动画 模板 ,多条件触发器,还有布局 本人博 ...
- WPF Popup 控件导致被遮挡内容不刷新的原因
WPF Popup 控件导致被遮挡内容不刷新的原因 周银辉 今天在写一个WPF控件时用到了Popup控件,很郁闷的情况是:当popup关闭时,原来被popup挡住的界面部分不刷新,非要手动刷新一下(比 ...
- 创建 WPF 工具箱控件
创建 WPF 工具箱控件 WPF (Windows Presentation Framework) 工具箱控件模板允许您创建 WPF 控件,会自动添加到 工具箱 安装扩展的安装. 本主题演示如何使用模 ...
- wpf打印控件 实现分页打印控件功能
因为 要实现打印 wpf listbox控件 数据特别多 要打印在 几张纸上 找了几天 都没有找到相关的例子 现在 解决了 在这里和大家分享一下 public void print(Fram ...
- WPF 分页控件 WPF 多线程 BackgroundWorker
WPF 分页控件 WPF 多线程 BackgroundWorker 大家好,好久没有发表一篇像样的博客了,最近的开发实在头疼,很多东西无从下口,需求没完没了,更要命的是公司的开发从来不走正规流程啊, ...
- WPF Image控件中的ImageSource与Bitmap的互相转换
原文:WPF Image控件中的ImageSource与Bitmap的互相转换 1.从bitmap转换成ImageSource [DllImport("gdi32.dll", ...
- 【转】WPF - 第三方控件
WPF - 第三方控件 目前第三方控件在网上形成巨大的共享资源,其中包括收费的也有免费的,有开源的也有不开源的,合理的使用第三方控件将使项目组的工作事半功倍.比如项目中有些复杂的业务逻辑.有些绚丽的效 ...
- WPF布局控件与子控件的HorizontalAlignment/VerticalAlignment属性之间的关系
WPF布局控件与子控件的HorizontalAlignment/VerticalAlignment属性之间的关系: 1.Canvas/WrapPanel控件: 其子控件的HorizontalAlign ...
随机推荐
- Jedis 源代码阅读一 —— Jedis
这是jedis 源代码文件夹,我们接下来选择性阅读重要的接口以及实现. └─redis └─clients ├─jedis │ │ BinaryClient.java │ │ BinaryJedis. ...
- 【死磕Java并发】—–J.U.C之AQS(一篇就够了)
[隐藏目录] 1 独占式 1.1 独占式同步状态获取 1.2 独占式获取响应中断 1.3 独占式超时获取 1.4 独占式同步状态释放 2 共享式 2.1 共享式同步状态获取 2.2 共享式同步状态释放 ...
- ### Hibernate中的事务与并发 ###
**事务相关的概念** 1. 什么是事务 * 事务就是逻辑上的一组操作,组成事务的各个执行单元,操作要么全都成功,要么全都失败. * 转账的例子:冠希给美美转钱,扣钱,加钱.两个操作组成了一个事情! ...
- 用DOM4J包实现对xml文件按属性分离。
转自本人博客:http://www.xgezhang.com/dom4j_xml_separata.html dom4j是一个Java的XML API.类似于jdom.用来读写XML文件的. dom4 ...
- 开发自己的PHP MVC框架(一)
这个教程能够使大家掌握用mvc模式开发php应用的基本概念.此教程分为三个部分.如今这篇是第一部分. 如今市面上有非常多流行的框架供大家使用.可是我们也能够自己动手开发一个mvc框架.採用mvc模式能 ...
- BZOJ 2096 Pilots - 单调队列STL(deque)
传送门 分析: 单调队列:维护两个递增.递减的队列,每次都加入新元素并更新,如果最大值(递减队首)-最小值(递增队首) > k,那么将最左段更新为前面两者中较前的那一个,并弹掉.用deque可以 ...
- 【u115】&&【t031】 01迷宫
01迷宫(maze01) Time Limit: 1 second Memory Limit: 128 MB [问题描述] 有一个仅由数字0与1组成的n×n格迷宫.若你位于一格0上,那么你可以移动到相 ...
- 【codeforces 791B】Bear and Friendship Condition
[题目链接]:http://codeforces.com/contest/791/problem/B [题意] 给你m对朋友关系; 如果x-y是朋友,y-z是朋友 要求x-z也是朋友. 问你所给的图是 ...
- C语言检查本机公网IP并发送邮件
这是一个用来获取本机公网IP地址,并检查是否是配置里保存的IP地址,假设不是,就向指定的邮箱发送一个邮件,报告这个IP地址的一段小代码.放到开机启动中,电脑不设password的时候万一丢了,还能有个 ...
- [Android]Fragment自定义动画、动画监听以及兼容性包使用
Fragment是Android在API 11之后加入的一个组件,对提高Android开发中的布局合理性和布局效率都有很大作用,尤其是在Android平板等大屏幕设备的开发中,Fragment的引入能 ...