最近要用WPF写一个树,同事给了我一个Demo(不知道是从哪里找来的),我基本上就是参照了这个Demo。

先放一下效果图(3棵树):

这个树索要满足的条件是:

  1. 父节点.Checked=true时,子节点全部选中(反之成立);
  2. 父节点.Checked=false时,子节点全部不选中(反之成立);
  3. 子节点存在部分节点选中,部分节点未选中时,父节点为非全选状态(null)(反之成立);

那么这个树究竟要怎么造出来呢?

由于用WPF,且用MVVM模式,故TreeView的ItemSource及复选框的选中状态IsChecked需要从ViewModel层进行绑定。先看一下树的xaml:

<Window x:Class="MyWpfCheckTreeDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:VM="clr-namespace:MyWpfCheckTreeDemo.AppViewModel"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
Title="MainWindow" Height="350" Width="525" Loaded="LoadedEvent">
<Window.Resources>
<HierarchicalDataTemplate x:Key="MyTreeItemTemplate"
DataType="{x:Type VM:CommonTreeView}"
ItemsSource="{Binding Path=Children,Mode=OneWay}">
<StackPanel x:Name="My_SP" Orientation="Horizontal" Margin="2">
<CheckBox IsChecked="{Binding Path=IsChecked}" >
</CheckBox>
<ContentPresenter Content="{Binding Path=NodeName,Mode=OneTime}" Margin="2,0"/>
</StackPanel>
</HierarchicalDataTemplate>
<Style x:Key="TreeViewItemStyle" TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded" Value="True" />
</Style>
</Window.Resources>
<Grid>
<TreeView Grid.Row="1" x:Name="tv" ItemsSource="{Binding MyTrees}"
ItemContainerStyle="{StaticResource TreeViewItemStyle}"
ItemTemplate="{StaticResource MyTreeItemTemplate}">
</TreeView>
</Grid>
</Window>

TreeView.xaml

在xaml中的数据绑定好之后,就是在后台如何实现数据的传递了。

先来看一下每个节点所需要包含的数据:

  • 节点名称:NodeName,
  • 父节点:Parent ,
  • 该父节点的所有孩子:Children,为每一个节点增加创建孩子的方法
  • 每个节点的选中状态:IsChecked,每次子节点的IsChecked变化时,需要去更新Parent节点的IsChecked.

现在将上述数据封装成一个树节点类:

    public  class CommonTreeView : NotifyPropertyBase
{
/// <summary>
/// 父
/// </summary>
public CommonTreeView Parent
{
get;
set;
} /// <summary>
/// 子
/// </summary>
public List<CommonTreeView> Children
{
get;
set;
} /// <summary>
/// 节点的名字
/// </summary>
public string NodeName
{
get;
set;
} public bool? _isChecked;
/// <summary>
/// CheckBox是否选中
/// </summary>
public bool? IsChecked
{
get
{
return _isChecked;
}
set
{
SetIsChecked(value, true, true);
}
} public CommonTreeView(string name)
{
this.NodeName=name;
this.Children=new List<CommonTreeView>();
}
public CommonTreeView() { } private void SetIsChecked(bool? value, bool checkedChildren, bool checkedParent)
{
if (_isChecked == value) return;
_isChecked = value;
//选中和取消子类
if (checkedChildren && value.HasValue && Children != null)
Children.ForEach(ch => ch.SetIsChecked(value, true, false)); //选中和取消父类
if (checkedParent && this.Parent != null)
this.Parent.CheckParentCheckState(); //通知更改
this.SetProperty(x => x.IsChecked);
} /// <summary>
/// 检查父类是否选 中
/// 如果父类的子类中有一个和第一个子类的状态不一样父类ischecked为null
/// </summary>
private void CheckParentCheckState()
{
List<CommonTreeView> checkedItems = new List<CommonTreeView>();
string checkedNames = string.Empty;
bool? _currentState = this.IsChecked;
bool? _firstState = null;
for (int i = 0; i < this.Children.Count(); i++)
{
bool? childrenState = this.Children[i].IsChecked;
if (i == 0)
{
_firstState = childrenState;
}
else if (_firstState != childrenState)
{
_firstState = null;
}
}
if (_firstState != null) _currentState = _firstState;
SetIsChecked(_firstState, false, true);
} /// <summary>
/// 创建树
/// </summary>
/// <param name="children"></param>
/// <param name="isChecked"></param> public void CreateTreeWithChildre( CommonTreeView children,bool? isChecked)
{
this.Children.Add(children);
//必须先把孩子加入再为Parent赋值,
//否则当只有一个子节点时Parent的IsChecked状态会出错 children.Parent = this;
children.IsChecked = isChecked;
}
}

CommonTreeView.cs

节点值变化时对UI进行通知的方法PropertyNotify:

    public class NotifyPropertyBase : INotifyPropertyChanged
{
public void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
} /// <summary>
/// 扩展方法
/// 避免硬编码问题
/// </summary>
public static class NotifyPropertyBaseEx
{
public static void SetProperty<T, U>(this T tvm, Expression<Func<T, U>> expre) where T : NotifyPropertyBase, new()
{
string _pro = CommonFun.GetPropertyName(expre);
tvm.OnPropertyChanged(_pro);
}//为什么扩展方法必须是静态的
} public class CommonFun
{
/// <summary>
/// 返回属性名
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="U"></typeparam>
/// <param name="expr"></param>
/// <returns></returns>
public static string GetPropertyName<T, U>(Expression<Func<T, U>> expr)
{
string _propertyName = "";
if (expr.Body is MemberExpression)
{
_propertyName = (expr.Body as MemberExpression).Member.Name;
}
else if (expr.Body is UnaryExpression)
{
_propertyName = ((expr.Body as UnaryExpression).Operand as MemberExpression).Member.Name;
}
return _propertyName;
}
}

INotifyPropertyChanged

到这里基本上这个树就可以投入使用了,现在在ViewModel中给树赋值,并取出选中状态的叶子的节点名称:
这个里面的方法只给出重点部分:

  /// <summary>
/// 创建树
/// </summary>
/// <returns></returns>
public List<CommonTreeView> MyCreateTree()
{
List<CommonTreeView> views = new List<CommonTreeView>();
//CommonTreeView _myT = new CommonTreeView("合约");
CommonTreeView _myy = new CommonTreeView("CCP");
views.Add(_myy);
CommonTreeView _myy1 = new CommonTreeView("CCP_1");
_myy.CreateTreeWithChildre(_myy1, true);
CommonTreeView _myy1_1 = new CommonTreeView("CCP_1.1");
_myy1.CreateTreeWithChildre(_myy1_1, true);
} /// <summary>
/// 选中的节点名称保存在_names中
/// </summary>
public void SaveC()
{
_names = new List<string>();
//SelectedTree=MyTrees.FindAll(r => r.IsChecked == true);
foreach (CommonTreeView tree in MyTrees)
{
GetCheckedItems(tree);
}
} /// <summary>
/// 获取选中项
/// </summary>
/// <param name="tree"></param>
private void GetCheckedItems(CommonTreeView tree)
{
if (tree.Parent != null && (tree.Children == null || tree.Children.Count == 0))
{
if (tree.IsChecked.HasValue && tree.IsChecked == true)
_names.Add(tree.NodeName);
}
else if (tree.Children != null && tree.Children.Count > 0)
{
foreach (CommonTreeView tv in tree.Children)
GetCheckedItems(tv);
}
}

TreeViewModel.cs

到这里就结束啦。。。

WPF:带复选框CheckBox的树TreeView的更多相关文章

  1. easyUI带复选框的组合树

    代码: <input id="depts"><script type="text/javascript">$(document).rea ...

  2. 雷林鹏分享:jQuery EasyUI 树形菜单 - 创建带复选框的树形菜单

    jQuery EasyUI 树形菜单 - 创建带复选框的树形菜单 easyui 的树(Tree)插件允许您创建一个复选框树.如果您点击一个节点的复选框,这个点击的节点信息将向上和向下继承.例如:点击 ...

  3. 使用CSS3美化复选框checkbox

    我们知道HTML默认的复选框样式十分简陋,而以图片代替复选框的美化方式会给页面表单的处理带来麻烦,那么本文将结合实例带您一起了解一下使用CSS3将复选框checkbox进行样式美化,并且带上超酷的滑动 ...

  4. jquery完成带复选框的表格行高亮显示

    jquery完成带复选框的表格行高亮显示 通过jquery技术来操作表格是件简单的事,通过jquery的语法,可以很轻松的完成表格的隔行换色,悬浮高亮,在实际的应用中可能会出现表格中带复选框的,删除时 ...

  5. css3美化复选框checkbox

     两种美化效果如下图: 代码(html) <div id="main"> <h2 class="top_title">使用CSS3美化复 ...

  6. [原创]纯JS实现网页中多选复选框checkbox和单选radio的美化效果

    图片素材: 最终效果图: <html><title> 纯JS实现网页中多选复选框checkbox和单选radio的美化效果</title><head>& ...

  7. 复选框(checkbox)、单选框(radiobox)的使用

    复选框(checkbox).单选框(radiobox)的使用 复选框: HTML: // 复选框 <input type="checkbox" name="chec ...

  8. php 判断复选框checkbox是否被选中

    php 判断复选框checkbox是否被选中   复选框checkbox在php表单提交中经常被使用到,本文章通过实例向大家介绍php如何判断复选框checkbox中的值是否被选中,需要的朋友可以参考 ...

  9. jquery判断复选框checkbox是否被选中

    jquery判断复选框checkbox是否被选中 使用is方法 //如果选中返回true //如果未选中返回false .is(':checked');

随机推荐

  1. 变量在SSIS包中的使用

    2010~2011年经常使用SSIS包采集加工数据,后来换了工作就很少使用.最近又开始用那玩意采集数据,努力回想之前是怎样操作的,网上各种找各种纠结.趁这次使用记录下日常操作步骤,以备以后不时之需. ...

  2. [原创]java WEB学习笔记98:Spring学习---Spring Bean配置及相关细节:如何在配置bean,Spring容器(BeanFactory,ApplicationContext),如何获取bean,属性赋值(属性注入,构造器注入),配置bean细节(字面值,包含特殊字符,引用bean,null值,集合属性list map propert),util 和p 命名空间

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

  3. WIN7远程桌面连接方法!

    WIN7远程桌面连接方法!

  4. javascript中的自增与自减

    一直都对自增与自减的执行顺序有点糊涂,今天查了资料,来总结一下 a++(a--),就是指当时计算a,当下一次使用这个变量的时候才执行++或者-- ++a(--a),就是指当时就计算++或者-- 例1: ...

  5. Oracle常用日期函数

    常用的时间格式掩码如下:掩码元素       含义YYYY           四位数年份 (如:2005)     yearYY             二位数年份(如  05) Q         ...

  6. HTML5 属性 认知

    HTML5中 不支持  Html4.01的属性: <acronym> <applet> <basefont> <big> <center> ...

  7. 34、JS/AJAX

      1)回顾JS中核心内容 2)了解WEB1.0和WEB2.0时代的技术与特点 3)理解AJAX的产生背景.工作原理与特点 4)掌握AJAX常用API及应用   声明:服务端使用Servlet技术 一 ...

  8. datagridview随窗体的大小而变,表格填满控件

    在C#winform布局的时候,我们拖一个datagridview到窗体上面,将datagridview调整为适合窗体的大小,但是我们运行之后,点击最大化按钮的时候,却发现datagridview的大 ...

  9. gfortran、g77等编译器中使用多个文件

    gfortran aaaa.f90 bbbb.f90 -o cccc (生成cccc可执行文件,cccc名称可自由设定) 又可以分成两步,因为gfortran先把程序文件编译成*.o文件,再把*.o文 ...

  10. js中的什么时候需要用new来实例化?

    有人说js中函数和类就是一个概念,请问:1 为什么我们在大多数情况下没有用new来实例化一个类(函数),如下 JavaScript code   1 2 3 4 5 6 7 <script> ...