当前位置:首页 > Windows程序 > 正文

WPF:带复选框CheckBox的树TreeView

2021-03-25 Windows程序

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

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

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

父节点.Checked=true时,子节点全部选中(反之成立);

父节点.Checked=false时,子节点全部不选中(反之成立);

子节点存在部分节点选中,部分节点未选中时,父节点为非全选状态(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:

温馨提示: 本文由Jm博客推荐,转载请保留链接: https://www.jmwww.net/file/67560.html