How to set / reset Checkbox value for three states in WPF

I have a data grid whose one of the header columns is a flag of three states. The celltemplate for this column contains two status flags + AllItems CheckBox - Item1 - Item2 - Item3 .. I wanted to use the AllItems flag to select / deselect all elements (item1, item2), which works fine. Next, I wanted to set the AllItems flag to an intermediate state when not all elements are selected / not selected. In the same way, I wanted to set the AllItems flag as checked / unchecked when all items are selected manually.

Here is the code I tried ...

<dg:DataGridTemplateColumn.HeaderTemplate> <DataTemplate> <StackPanel x:Name="StackPanelForItemCheckbox" Orientation="Horizontal"> <CheckBox x:Name="AllItemSelectionCheckBox" HorizontalAlignment="Left" Cursor="Hand" IsChecked="{Binding IsAllItemChecked, Mode=TwoWay}" IsThreeState="True" Checked="ItemSelectionCheckBox_Checked" Unchecked="ItemSelectionCheckBox_Unchecked" Click="AllItemSelectionCheckBox_Click"> <TextBlock x:Name="ItemNameTextBlock" Text="Item" Margin="10,0,0,0"> ...... <dg:DataGridTemplateColumn.CellTemplate> <DataTemplate x:Name="ItemCheckDataTemplate"> <StackPanel x:Name="ItemCheckBoxStackPanel" Orientation="Horizontal"> <CheckBox x:Name="itemCheckBox" Cursor="Hand" IsChecked="{Binding IsItemChecked, Mode=TwoWay}" Click="ItemSelectionCheckBox_Click"></CheckBox> <TextBlock x:Name="ItemNameTextBlock" Text="{Binding Path=Item}"> </TextBlock> </StackPanel> </DataTemplate> ... 

The ItemSelectionCheckBox_Click method looks for all three states ("everything is checked", "not checked", "intermediate") and sets the property "IsAllItemChecked", which is INotifyproperty. This does not work. Another alternative that I can try is to find the "AllItems" element and install it from the code. I can not find anything like this on the Internet. There are a few examples, but this is for TreeView, and not the way I'm trying. Any help?

PS >>

Updated with a fix to close this post.

  • First of all, I wanted the "AllItemSelectionCheckBox" to have only two states (True, False) when manually selected.

     private void AllItemSelectionCheckBox_Click(object sender, RoutedEventArgs e) { var cb = e.Source as CheckBox; if (!cb.IsChecked.HasValue) cb.IsChecked = false; } 
  • I wanted the "AllItemSelectionCheckBox" checkbox to display three-state code.
  • All checked flags will result in a value of TRUE
  • If unchecked, its value will be FALSE.
  • Any multiple selected will be NULL.

The sample code is as follows:

 private void itemCheckBox_Checked(object sender, RoutedEventArgs e) { DataGridRowsPresenter DGRPresenter = FindVisualChild<DataGridRowsPresenter>(DataGName1); if (DGRP == null || DGRP.Children == null) return null; foreach (object obj in UIEC) { DGR = obj as Microsoft.Windows.Controls.DataGridRow; UIC = DGR.Item as <datagrid mapped data model>; if (DGR.IsSelected == true) UIC.IsItemChecked = true; if (UIC.IsItemChecked == true) NumberOfItemsChecked++; } if (NumberOfItemsChecked == myViewModelAllItems.Count) { allcheckbox.IsChecked = true; } else if (NumberOfItemsChecked < myViewModelAllItems.Count) { allcheckbox.IsChecked = null; //intermittent state } } 

The global update of the NumberOfItemsChecked counter did not work due to the race condition leading to a distortion of the value outside.

Note. The above code is more like an example and may not work if you copy it directly. I can provide a complete code with a sample on request.

+6
checkbox wpf wpf-controls wpfdatagrid
source share
4 answers

In fact, I felt better.

I found out that if I create a binding for IsThreeState, change the value based on whether the value is set or not, then it works.

 bool? _Value; public bool? Value { get { return _Value; } set { if (value == null) { IsThreeState = true; } else { IsThreeState = false; } _Value = value; NotifyPropertyChanged("Value"); } } bool _IsThreeState = true; public bool IsThreeState { get { return _IsThreeState; } private set { _IsThreeState = value; NotifyPropertyChanged("IsThreeState"); } } 

Now the flag will support trreestate IFF, the value will be set to zero from the outside. If true or false, the user cannot set it to null.

+14
source share

I found a simple way:

Check the event box for the three states and check if its value is empty. If so, change it to false. Like this:

  private void cbAllFeatures_Click(object sender, RoutedEventArgs e) { if (cbAllFeatures.IsChecked != null) return; cbAllFeatures.IsChecked = false; } 

I hope you will like it.

+1
source share

This is what worked for me. I created a new FTThreeStateCheckBox (subclassed from CheckBox), overriding the IsCheckedProperty metadata, so I could follow the changes in the value, and then if it was null, I set IsThreeState and IsChecked to false.

 static FTThreeStateCheckBox() { IsCheckedProperty.OverrideMetadata(typeof(FTThreeStateCheckBox), new FrameworkPropertyMetadata(null, IsCheckedChanged)); } public static void IsCheckedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if ((d as FTThreeStateCheckBox).IsChecked == null) { (d as FTThreeStateCheckBox).IsThreeState = false; (d as FTThreeStateCheckBox).IsChecked = false; } } 
0
source share

for people who want to achieve this

  • the user can only set the flag in the view to true or false. Undefined!
  • the code in the ViewModel should be able to check the indefinite

just do it:

  • add a flag to view, but do not set IsThreeState=true
  • bind IsChecked to bool? property bool? (nullable bool) in ViewModel

Now you can set it to null in the ViewModel, while the user cannot do this in the View.

0
source share

All Articles