如何实现treeview形式的checkbox,并且父节点和子节点的选中状态可相互影响。示例图:
代码如下:
wpf代码:treeview绑定的数据是PermissionDataCollection。
<TreeView ItemsSource="{Binding PermissionDataCollection}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children}">
<StackPanel Orientation="Horizontal" >
<CheckBox IsChecked="{Binding IsChecked}"/>
<TextBlock Text="{Binding Name}"/>
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
后端数据来源:PermissionDataCollection的声明及定义:
public ObservableCollection<TreeViewItemModel> PermissionDataCollection { get; set; }
PermissionDataCollection = new ObservableCollection<TreeViewItemModel>();
// 添加根节点
var rootNode = new TreeViewItemModel { Name = "所有权限", IsChecked = false, Children = new ObservableCollection<TreeViewItemModel>() };
PermissionDataCollection0.Add(rootNode);
// 添加子节点
var childNode1 = new TreeViewItemModel { Name = "系统设置", IsChecked = false, Children = new ObservableCollection<TreeViewItemModel>(), Parent = rootNode };
var childNode2 = new TreeViewItemModel { Name = "日志管理", IsChecked = true, Children = new ObservableCollection<TreeViewItemModel>(), Parent = rootNode };
rootNode.Children.Add(childNode1);
rootNode.Children.Add(childNode2);
// 添加孙子节点
var grandChildNode1 = new TreeViewItemModel { Name = "相机设置", IsChecked = true, Children = new ObservableCollection<TreeViewItemModel>(), Parent = childNode1 };
var grandChildNode2 = new TreeViewItemModel { Name = "参数设置", IsChecked = false, Children = new ObservableCollection<TreeViewItemModel>(), Parent = childNode1};
childNode1.Children.Add(grandChildNode1);
childNode1.Children.Add(grandChildNode2);
TreeViewItemModel的定义:(也就是定义treeview形式的checkbox)
public class TreeViewItemModel : INotifyPropertyChanged
{
private bool _isChecked;
private bool _isUpdatingChildren;
public string Name { get; set; }
public bool IsChecked
{
get { return _isChecked; }
set
{
if (_isChecked != value)
{
_isChecked = value;
OnPropertyChanged(nameof(IsChecked));
if (!_isUpdatingChildren && Children != null)
{
_isUpdatingChildren = true;
// 递归设置子节点的勾选状态
foreach (var child in Children)
{
child.IsChecked = value;
}
_isUpdatingChildren = false;
}
// 更新父节点的勾选状态
if (Parent != null)
{
UpdateParentCheckedState();
}
}
}
}
public ObservableCollection<TreeViewItemModel> Children { get; set; }
public TreeViewItemModel Parent { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public void UpdateParentCheckedState()
{
if (Parent != null)
{
bool allSiblingsChecked = Parent.Children.All(child => child.IsChecked);
bool anySiblingChecked = Parent.Children.Any(child => child.IsChecked);
if (allSiblingsChecked)
{
Parent._isChecked = true;
}
else if (anySiblingChecked)
{
Parent._isChecked = false;
}
else
{
Parent._isChecked = false;
}
Parent.OnPropertyChanged(nameof(IsChecked));
Parent.UpdateParentCheckedState();
}
}
}