kir*_*arG 4 wpf checkbox treeview
我有一个要求,我需要TreeView动态添加节点,并使用CheckBoxes 添加节点.如果CheckBox选择了一个孩子也被选中.
主要是我想TreeView动态添加数据.
Rob*_*ney 14
一旦你知道如何,这非常简单.
CheckableItem为树视图项数据创建一个视图模型类(我在这里调用它).它需要这三件事:
Children类型的属性ObservableCollection<CheckableItem>.IsChecked类型的属性Visibility,在其setter中,它会引发PropertyChanged并遍历项目Children并设置它们的IsChecked属性.在此类中实现其他属性以将项目的数据公开给绑定(我的示例只是假定调用了某些内容Value).或者你可以实现一个Item类的类object并ContentPresenter在模板中使用a ,但我会留意你.
现在HierarchicalDataTemplate为您的类创建一个如下所示的类:
<HierarchicalDataTemplate
DataType="{x:Type local:CheckableItem}"
ItemsSource="{Binding Children}">
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding IsChecked}"/>
<TextBlock Text="{Binding Value}"/>
</StackPanel>
</HierarchicalDataTemplate>
Run Code Online (Sandbox Code Playgroud)
...并TreeView使用它(我假设你已经填充了这些对象的集合,当然):
<TreeView ItemsSource="{Binding MyCollectionOfCheckableItems}"/>
Run Code Online (Sandbox Code Playgroud)
工作原理:TreeView使用它HierarchicalDataTemplate来渲染其中的每个项目ItemsSource.这HierarchicalDataTemplate是一个模板,它创建一个HeaderedItemsControl(在这种情况下为a TreeViewItem),使用它的模板来呈现标题,然后使用它ItemsSource作为控件项的源 - 由于它们都是CheckableItems,因此被转换为TreeViewItems HierarchicalDataTemplate.在那之后,它一直是乌龟.
这是一个非常好的概述TreeView实际上如何实际工作,虽然我发现的大多数例子,它有很多花里胡哨,很难看出基本原则是多么简单.如果你了解MVVM,那么前一段是你需要知道的90%.
pr0*_*g3r 10
看一下这个:

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; }
}
}
Run Code Online (Sandbox Code Playgroud)
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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
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>
</TreeView>
<Button Content="?" Click="Button_PrintCrew_Click" />
<TextBlock x:Name="textBoxCrew"/>
</StackPanel>
</Window>
Run Code Online (Sandbox Code Playgroud)
MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
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 WpfApplication102
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public ObservableCollection<Family> Families { get; set; }
public MainWindow()
{
InitializeComponent();
this.Families = new ObservableCollection<Family>();
this.Families.Add(new Family() { Name = "Simpsons", Members = new List<Person>() { new Person() { Name = "Homer" }, new Person() { Name = "Bart" } } });
this.Families.Add(new Family() { Name = "Griffin", Members = new List<Person>() { new Person() { Name = "Peter" }, new Person() { Name = "Stewie" } } });
this.Families.Add(new Family() { Name = "Fry", Members = new List<Person>() { new Person() { Name = "Philip J." } } });
foreach (Family family in this.Families)
foreach (Person person in family.Members)
person.SetValue(ItemHelper.ParentProperty, family);
}
private void Button_PrintCrew_Click(object sender, RoutedEventArgs e)
{
string crew = "";
foreach (Family family in this.Families)
foreach (Person person in family.Members)
if (ItemHelper.GetIsChecked(person) == true)
crew += person.Name + ", ";
crew = crew.TrimEnd(new char[] { ',', ' ' });
this.textBoxCrew.Text = "Your crew: " + crew;
}
}
}
Run Code Online (Sandbox Code Playgroud)