Posts Tagged ‘TextBox’

The Three-State CheckBox

October 21, 2009 2 comments

In my previous post I explained why you should use the ‘CustomControl (WPF)’ template from the Add New Item dialog when you want to create a custom control. But of course there’s an exception to this rule! When you only want to make (minor) changes to the functionality of a base control, you don’t always need the stuff that Visual Studio generates for you. That stuff is generated so you can create your own presentation (ControlTemplate) for your control. But what if you only want to change the logic?

Consider the following scenario:

Some people want to use the CheckBox’s ‘Indeterminate’ state as a representation for ‘the user hasn’t made a choice yet’. And if you’re like me, if I click on a checkbox I expect it to go into its Checked state. And if you combine these facts you might find it annoying that when you click on an Indeterminate checkbox, it turns Unchecked, instead of Checked.

Now, can we fix this without all the stuff that Visual Studio generates for you? After all, we don’t want to change the presentation of the checkbox or its states, just the sequence order of the states. The answer is: yes, of course we can!

In this case we don’t use the ‘CustomControl’ template, but we just add a new Class to our project. Taking this road, we don’t have the automatically generated static constructor with the DefaultStyleKey override in our class, but that’s fine, because in our scenario we explicitly don’t want an override to tell WPF to use a custom control template. We just want the standard control template to be used.

Now we only have to make our class inherit from the standard CheckBox and implement our modification:

public class CustomThreeStateCheckBox : CheckBox
    public CustomThreeStateCheckBox()
        // Always start in the 'Indeterminate' state
        base.IsChecked = null;

    protected override void OnToggle()
        // Change the sequence from: Unchecked - Checked - Indeterminate
        // to: Indeterminate - Checked - Unchecked
        if (this.IsChecked == false)
            this.IsChecked = this.IsThreeState ? null : ((bool?)true);
            this.IsChecked = new bool?(!this.IsChecked.HasValue);

Another example of a ‘semi-custom’ control could be a numeric TextBox. If you just want to ignore any character that cannot be parsed to a double, this simple class might be all you need:

public class NumericTextBox : TextBox
    protected override void OnPreviewTextInput(System.Windows.Input.TextCompositionEventArgs e)
        // Ignore any character that fails to parse to a double
        double value;
        if (!Double.TryParse(e.Text, out value))
            e.Handled = true;

The advantage of these kinds of custom controls is that it’s less work and they will respect the Windows theme your application is running in, without having to create several different theme-styles for them.

So, every time you’re about to create a custom control, take the time to check if you really need a new control template, because it’s time well spent!

Download source code.