I'm working in WPF and i have an interesting requirement. I need my checkboxes to be ThreeState, so if only some of the child elements are selected it shows as indeterminate. But when a use clicks it, i want it to select either true or false.
Here is a story to represent my requirements:
item - indeterminate
subItem - checked
subItem - unchecked
subItem - checked
When a user clicks item
, the checkbox should alternate between checked and unchecked. The user should never be able to select 'indeterminate' as a state. Is this possible?
Checkboxes actually has three states: true, false and indeterminate which indicates that a checkbox is neither "on" or "off". A checkbox cannot be set to indeterminate state by an HTML attribute - it must be set by a JavaScript. This state can be used to force the user to check or uncheck the checkbox.
Primer: An HTML checkbox can be set as indeterminate , which displays it as neither checked nor unchecked. Even in this indeterminate state, there is still an underlying boolean checked state. When an indeterminate checkbox is clicked, it loses its indeterminate state.
A tri-state checkbox can be checked, not checked, or partially checked. The condition of being partially checked is based on the selection of child elements. If all child elements are selected, the parent checkbox is checked.
Noun. indeterminate state (plural indeterminate states) (grammar) A noun form occurring in Afroasiatic languages, when the noun does not bear a determiner – where it would use the determinate state –, nor governs a noun – where it would use the construct state.
XAML:
<CheckBox IsThreeState="True" IsChecked="{x:Null}" Click="CheckBox_Clicked" />
Code-behind:
private void CheckBox_Clicked(object sender, RoutedEventArgs e)
{
var cb = e.Source as CheckBox;
if (!cb.IsChecked.HasValue)
cb.IsChecked = false;
}
If you don't like the code-behind solution, then you could sub-class your own control like in the solution for this question.
It's much easier if you use Binding with your CheckBox.
XAML:
<Window x:Class="WpfApplication39Checkbox.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<CheckBox Content="CheckBox" HorizontalAlignment="Left" Margin="128,95,0,0" VerticalAlignment="Top" IsThreeState="False" IsChecked="{Binding CheckState}"/>
<Button Content="Button" HorizontalAlignment="Left" Margin="46,241,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
<Button Content="Button" HorizontalAlignment="Left" Margin="139,241,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click_1"/>
<Button Content="Button" HorizontalAlignment="Left" Margin="235,241,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click_2"/>
</Grid>
</Window>
Code-behind:
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;
namespace WpfApplication39Checkbox
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window, INotifyPropertyChanged
{
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
private bool? checkState;
public bool? CheckState
{
get { return checkState; }
set
{
checkState = value;
OnPropertyChanged("CheckState");
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
CheckState = false;
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
CheckState = true;
}
private void Button_Click_2(object sender, RoutedEventArgs e)
{
CheckState = null;
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
You see the point? You set the CheckBox to IsThreeState="False" but set the third state from CodeBehind and the CheckBox behaves as expected.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With