Hi,
I am stuck at making threestate checkbox.
I have created the sample as shown in below. When child items are selected Parent checkbox should show Check/Uncheck/Indetermine
Could anyone help on the below code to make it work threestate of checkbox?
Thanks in advance.
What I have tried:
Window.xaml:
<Window x:Class="SampleLV.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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:SampleLV"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ListView x:Name="listview">
<!-- View -->
<ListView.View>
<GridView>
<GridViewColumn Width="50">
<GridViewColumn.CellTemplate>
<DataTemplate DataType="cls:Item">
<CheckBox IsChecked="{Binding Selected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Checked="CheckBox_Checked" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Width="300" Header="Name" DisplayMemberBinding="{Binding Name, UpdateSourceTrigger=PropertyChanged}"></GridViewColumn>
<GridViewColumn Width="100" Header="Type" DisplayMemberBinding="{Binding Type}"></GridViewColumn>
</GridView>
</ListView.View>
<!-- Group style -->
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Expander x:Name="exp" IsExpanded="True">
<Expander.Header>
<StackPanel Orientation="Horizontal">
<CheckBox Checked="OnGroupChecked" IsThreeState="True" IsChecked="{Binding DataContext.IsSelected, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Unchecked="OnGroupUnchecked"
Visibility="{Binding }"></CheckBox>
<TextBlock Text="{Binding Name}" />
<TextBlock Text="{Binding ItemCount, StringFormat='- {0} item(s)'}" />
</StackPanel>
</Expander.Header>
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</ListView.GroupStyle>
</ListView>
</Grid>
</Window>
Window.xaml.cs:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
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 SampleLV
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var lst = new List<item>();
lst.Add(new Item { Name = "A", Type = "1" });
lst.Add(new Item { Name = "B", Type = "1" });
lst.Add(new Item { Name = "C", Type = "1" });
lst.Add(new Item { Name = "A", Type = "2" });
lst.Add(new Item { Name = "B", Type = "2" });
lst.Add(new Item { Name = "C", Type = "2" });
listview.ItemsSource = lst;
var view = CollectionViewSource.GetDefaultView(lst);
view.GroupDescriptions.Add(new PropertyGroupDescription("Type"));
}
private void OnGroupChecked(object sender, RoutedEventArgs e)
{
this.HandleGroupCheck((CheckBox)sender, true);
}
private void HandleGroupCheck(CheckBox sender, bool check)
{
var group = (CollectionViewGroup)sender.DataContext;
this.HandleGroupCheckRecursive(group, check);
}
private void HandleGroupCheckRecursive(CollectionViewGroup group, bool check)
{
foreach (var itemOrGroup in group.Items)
{
if (itemOrGroup is CollectionViewGroup)
{
this.HandleGroupCheckRecursive(itemOrGroup as CollectionViewGroup, check);
}
else if (itemOrGroup is Item)
{
var item = (Item)itemOrGroup;
item.Selected = check;
}
}
}
private void OnGroupUnchecked(object sender, RoutedEventArgs e)
{
this.HandleGroupCheck((CheckBox)sender, false);
}
private void CheckBox_Checked(object sender, RoutedEventArgs e)
{
this.HandleChildCheck((CheckBox)sender, true);
}
private void HandleChildCheck(CheckBox sender, bool check)
{
var group = (Item)sender.DataContext;
group.IsSelected = true;
}
public static T GetVisualParent<t>(Visual referenceVisual) where T:Visual
{
Visual parent = referenceVisual;
while (parent !=null)
{
parent = VisualTreeHelper.GetParent(parent) as Visual;
if(parent !=null && parent.GetType() == typeof(T))
{
return parent as T;
}
}
return parent as T;
}
private void HandleChildGroupCheck(Item group, bool check)
{
}
}
public class Item : INotifyPropertyChanged
{
private string _name;
private bool _selected;
private string _type;
public string Name {
get { return _name; }
set {
_name = value;
this.OnPropertyChanged();
}
}
public bool Selected {
get { return _selected; }
set {
_selected = value;
this.OnPropertyChanged();
}
}
public string Type {
get { return _type; }
set {
_type = value;
this.OnPropertyChanged();
}
}
bool? _isSelected;
public bool? IsSelected {
get { return _isSelected; }
set {
_isSelected = value;
OnPropertyChanged("IsSelected");
}
}
protected virtual void OnPropertyChanged([CallerMemberName] string property = "")
{
if (this.PropertyChanged != null) this.PropertyChanged(this, new PropertyChangedEventArgs(property));
}
public event PropertyChangedEventHandler PropertyChanged;
}
}