带有复选框的 Controls.TreeView

1.定义 TreeView 模型
using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ViewTreeDemo { 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(); } } } }
2.在 ViewModel 中初始化 TreeView
using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ViewTreeDemo { public class MainWindowViewModel { public ObservableCollection<TreeViewItemModel> TreeDataCollection { get; set; } public MainWindowViewModel() { TreeDataCollection = new ObservableCollection<TreeViewItemModel>(); // 添加根节点 var rootNode = new TreeViewItemModel { Name = "所有权限", IsChecked = false, Children = new ObservableCollection<TreeViewItemModel>() }; TreeDataCollection.Add(rootNode); // 添加子节点 var childNode1 = new TreeViewItemModel { Name = "报表管理", IsChecked = false, Children = new ObservableCollection<TreeViewItemModel>(), Parent = rootNode }; var childNode2 = new TreeViewItemModel { Name = "系统设置", IsChecked = false, Children = new ObservableCollection<TreeViewItemModel>(), Parent = rootNode }; rootNode.Children.Add(childNode1); rootNode.Children.Add(childNode2); // 添加孙子节点 var grandChildNode1 = new TreeViewItemModel { Name = "角色管理", IsChecked = false, Children = new ObservableCollection<TreeViewItemModel>(), Parent = childNode1 }; var grandChildNode2 = new TreeViewItemModel { Name = "角色管理", IsChecked = false, Children = new ObservableCollection<TreeViewItemModel>(), Parent = childNode1 }; var grandChildNode3 = new TreeViewItemModel { Name = "参数设置", IsChecked = false, Children = new ObservableCollection<TreeViewItemModel>(), Parent = childNode2 }; childNode1.Children.Add(grandChildNode1); childNode1.Children.Add(grandChildNode2); childNode2.Children.Add(grandChildNode3); } } }
3.绘制 View
<Window x:Class="ViewTreeDemo.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:ViewTreeDemo" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" Title="MainWindow" Width="800" Height="450" mc:Ignorable="d"> <Window.DataContext> <local:MainWindowViewModel /> </Window.DataContext> <Window.Resources> <Style x:Key="ExpandCollapseToggleStyle" TargetType="ToggleButton"> <Setter Property="Focusable" Value="False" /> <Setter Property="Width" Value="16" /> <Setter Property="Height" Value="16" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="ToggleButton"> <Border HorizontalAlignment="Center" VerticalAlignment="Center" Width="26" Height="26" Background="Transparent"> <TextBlock x:Name="ExpandPath" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="22" Text="▸" /> </Border> <ControlTemplate.Triggers> <Trigger Property="IsChecked" Value="True"> <Setter TargetName="ExpandPath" Property="Text" Value="▾" /> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" /> <Style x:Key="Style_Default_TreeViewItem" TargetType="TreeViewItem"> <Setter Property="Background" Value="Transparent" /> <Setter Property="Padding" Value="0,5,0,0" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="TreeViewItem"> <StackPanel> <Border x:Name="Bd" Padding="{TemplateBinding Padding}" Background="{TemplateBinding Background}"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <ToggleButton x:Name="Expander" ClickMode="Press" IsChecked="{Binding IsExpanded, RelativeSource={RelativeSource TemplatedParent}}" Style="{StaticResource ExpandCollapseToggleStyle}" Visibility="{TemplateBinding HasItems, Converter={StaticResource BooleanToVisibilityConverter}}" /> <ContentPresenter x:Name="PART_Header" Grid.Column="1" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" ContentSource="Header" /> </Grid> </Border> <ItemsPresenter x:Name="ItemsHost" Margin="30,0,0,0" /> </StackPanel> <ControlTemplate.Triggers> <Trigger Property="IsExpanded" Value="False"> <Setter TargetName="ItemsHost" Property="Visibility" Value="Collapsed" /> </Trigger> <Trigger Property="IsSelected" Value="True"> <Setter TargetName="Bd" Property="Background" Value="Transparent" /> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> </Window.Resources> <Grid> <TreeView ItemsSource="{Binding TreeDataCollection}"> <TreeView.ItemContainerStyle> <Style BasedOn="{StaticResource Style_Default_TreeViewItem}" TargetType="TreeViewItem" /> </TreeView.ItemContainerStyle> <TreeView.ItemTemplate> <HierarchicalDataTemplate ItemsSource="{Binding Children}"> <StackPanel VerticalAlignment="Center" Orientation="Horizontal"> <CheckBox VerticalAlignment="Center" IsChecked="{Binding IsChecked}" /> <TextBlock VerticalAlignment="Center" Text="{Binding Name}" PreviewMouseDown="TextBlock_PreviewMouseDown" /> </StackPanel> </HierarchicalDataTemplate> </TreeView.ItemTemplate> </TreeView> </Grid> </Window>
using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; namespace ViewTreeDemo { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void TextBlock_PreviewMouseDown(object sender, MouseButtonEventArgs e) { if (sender is System.Windows.Controls.TextBlock textBlock && e.ClickCount == 1) { var parent = textBlock.Parent as StackPanel; if (parent != null) { var checkBox = parent.Children[0] as System.Windows.Controls.CheckBox; if (checkBox != null) { checkBox.IsChecked = !checkBox.IsChecked; } } } } } }

浙公网安备 33010602011771号