如何使用wpf中的复选框开发树视图?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何使用wpf中的复选框开发树视图?相关的知识,希望对你有一定的参考价值。

我有一个要求,我需要动态地向TreeView添加节点,并使用CheckBoxes添加节点。如果选择了一个CheckBox,也选择了孩子。

主要是我想动态地向TreeView添加数据。

答案

一旦你知道如何,这非常简单。

为树视图项数据创建一个视图模型类(我在这里称之为CheckableItem)。它需要这三件事:

  • 它必须实现INotifyPropertyChanged。
  • 它需要Children类型的ObservableCollection<CheckableItem>属性。
  • 它需要IsChecked类型的Visibility属性,在其setter中,提升PropertyChanged并且还遍历Children中的项目并设置它们的IsChecked属性。

在这个类中实现其他属性以将项的数据暴露给绑定(我的示例假设有一个名为Value的东西)。或者你可以实现一个类型为Itemobject类,并在模板中使用ContentPresenter,但我会留意你。

现在为你的类创建一个HierarchicalDataTemplate,看起来像这样:

<HierarchicalDataTemplate
    DataType="{x:Type local:CheckableItem}" 
    ItemsSource="{Binding Children}">
    <StackPanel Orientation="Horizontal">
        <CheckBox IsChecked="{Binding IsChecked}"/>
        <TextBlock Text="{Binding Value}"/>
    </StackPanel>
</HierarchicalDataTemplate>

...和使用它的TreeView(我假设你已经填充了这些对象的集合,当然):

<TreeView ItemsSource="{Binding MyCollectionOfCheckableItems}"/>

它是如何工作的:TreeView使用HierarchicalDataTemplate渲染其ItemsSource中的每个项目。 HierarchicalDataTemplate是一个创建HeaderedItemsControl(在这种情况下是TreeViewItem)的模板,使用其模板渲染标题,然后使用其ItemsSource作为控件项目的来源 - 由于它们都是CheckableItems,因此被转换为TreeViewItemHierarchicalDataTemplates。在那之后,它一直是乌龟。

This非常好地概述了TreeView在实践中是如何运作的,尽管我发现的大多数例子都有很多花里胡哨,但很难看出基本原理有多么简单。如果你了解MVVM,那么前一段是你需要知道的90%。

另一答案

看一下这个:

DataModel.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;

namespace WpfApplication102
{
    public class Family : DependencyObject
    {
        public string Name { get; set; }
        public List<Person> Members { get; set; }
    }

    public class Person : DependencyObject
    {
        public string Name { get; set; }
    }
}

ItemHelper.cs

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;

namespace WpfApplication102
{
    public class ItemHelper : DependencyObject
    {
        public static readonly DependencyProperty IsCheckedProperty = DependencyProperty.RegisterAttached("IsChecked", typeof(bool?), typeof(ItemHelper), new PropertyMetadata(false, new PropertyChangedCallback(OnIsCheckedPropertyChanged)));
        private static void OnIsCheckedPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is Family && ((bool?)e.NewValue).HasValue)
                foreach (Person p in (d as Family).Members)
                    ItemHelper.SetIsChecked(p, (bool?)e.NewValue);

            if (d is Person)
            {
                int checked = ((d as Person).GetValue(ItemHelper.ParentProperty) as Family).Members.Where(x => ItemHelper.GetIsChecked(x) == true).Count();
                int unchecked = ((d as Person).GetValue(ItemHelper.ParentProperty) as Family).Members.Where(x => ItemHelper.GetIsChecked(x) == false).Count();
                if (unchecked > 0 && checked > 0)
                {
                    ItemHelper.SetIsChecked((d as Person).GetValue(ItemHelper.ParentProperty) as DependencyObject, null);
                    return;
                }
                if (checked > 0)
                {
                    ItemHelper.SetIsChecked((d as Person).GetValue(ItemHelper.ParentProperty) as DependencyObject, true);
                    return;
                }
                ItemHelper.SetIsChecked((d as Person).GetValue(ItemHelper.ParentProperty) as DependencyObject, false);
            }
        }
        public static void SetIsChecked(DependencyObject element, bool? IsChecked)
        {
            element.SetValue(ItemHelper.IsCheckedProperty, IsChecked);
        }
        public static bool? GetIsChecked(DependencyObject element)
        {
            return (bool?)element.GetValue(ItemHelper.IsCheckedProperty);
        }

        public static readonly DependencyProperty ParentProperty = DependencyProperty.RegisterAttached("Parent", typeof(object), typeof(ItemHelper));
        public static void SetParent(DependencyObject element, object Parent)
        {
            element.SetValue(ItemHelper.ParentProperty, Parent);
        }
        public static object GetParent(DependencyObject element)
        {
            return (object)element.GetValue(ItemHelper.ParentProperty);
        }
    }
}

MainWindow.xaml

<Window x:Class="WpfApplication102.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication102"
        Title="MainWindow" Height="220" Width="250">

    <StackPanel>

        <TreeView x:Name="treeView" ItemsSource="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=Families}">
            <TreeView.Resources>
                <HierarchicalDataTemplate DataType="{x:Type local:Family}" ItemsSource="{Binding Members}" >
                    <CheckBox Content="{Binding Name}" IsChecked="{Binding Path=(local:ItemHelper.IsChecked), Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" >
                        <CheckBox.Style>
                            <Style TargetType="{x:Type CheckBox}">
                                <Setter Property="Foreground" Value="Black"/>
                                <Setter Property="Visibility" Value="Visible"/>
                                <Style.Triggers>
                                    <DataTrigger Binding="{Binding Path=(local:ItemHelper.IsChecked)}" Value="False" >
                                        <Setter Property="Foreground" Value="LightGray"/>
                                    </DataTrigger>
                                </Style.Triggers>
                            </Style>
                        </CheckBox.Style>
                    </CheckBox>
                </HierarchicalDataTemplate>
                <DataTemplate DataType="{x:Type local:Person}" >
                    <CheckBox Content="{Binding Name}" IsChecked="{Binding Path=(local:ItemHelper.IsChecked), Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" >
                        <CheckBox.Style>
                            <Style TargetType="{x:Type CheckBox}">
                                <Setter Property="Foreground" Value="Black"/>
                                <Setter Property="Visibility" Value="Visible"/>
                                <Style.Triggers>
                                    <DataTrigger Binding="{Binding Path=(local:ItemHelper.IsChecked)}" Value="False" >
                                        <Setter Property="Foreground" Value="LightGray"/>
                                    </DataTrigger>
                                </Style.Triggers>
                            </Style>
                        </CheckBox.Style>
                    </CheckBox>
                </DataTemplate>
            </TreeView.Resources>
            <TreeView.ItemContainerStyle>
                <Style TargetType="{x:Type TreeViewItem}">
                    <Setter Property="IsExpanded" Value="True"/>
                </Style>
            </TreeView.ItemContainerStyle&g

以上是关于如何使用wpf中的复选框开发树视图?的主要内容,如果未能解决你的问题,请参考以下文章

带有复选框的 C# WPF 目录树视图:检查构建项目失败,PropertyChanged 为空

如何从 WPF 树视图中删除边框

从 wpf 中的文件路径列表填充树视图

TreeView与CheckBoxes WPF

如何在wpf应用程序中使gridview成为树视图的子元素

当我取消选中自定义树视图中的子节点复选框时,如何取消选中所有父节点