Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Forcing a tri-state checkbox to not move to indeterminate state

Tags:

checkbox

wpf

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?

like image 784
TerrorAustralis Avatar asked Oct 13 '10 04:10

TerrorAustralis


People also ask

How to make checkbox indeterminate?

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.

What happens when you click an indeterminate 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.

What is a tri state checkbox?

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.

What is an indeterminate state?

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.


2 Answers

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.

like image 179
Bermo Avatar answered Sep 26 '22 01:09

Bermo


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.

like image 24
GreenEyedAndy Avatar answered Sep 23 '22 01:09

GreenEyedAndy