Click here to Skip to main content
Click here to Skip to main content

CheckBoxPanel - A C# CheckBox that auto-enables/disables related controls

, 18 Aug 2009 CPOL
Rate this:
Please Sign up or sign in to vote.
A simple .net Panel Control that allows a CheckBox to automatically enable/disable a group of related controls.

Introduction

CheckBoxPanel is a simple user control that groups a number of related controls. A 'Master' checkbox control is used to automatically enable/disable the group of controls. If the user clicks on any disabled control, the checkbox becomes checked and all the controls are enabled, improving the Form's workflow and significantly improving one aspect of your application's User Experience.

CheckBoxPanel.gif

Background

I'm always striving to improve my user interfaces. A common user interface approach is to present an option (for example: "Save to backup file") as a check box, with some additional related settings (e.g. An EditBox containing the filename to write to and a 'browse' button). Most conventional user interfaces either:

  • Leave the settings editable (argh!) when the main option is disabled, or
  • Disable the controls, only enabling them if the main option is first checked.

Let's make things better... When the controls are disabled, why should the user have to click the CheckBox to make them editable? If they click on a child TextBox we can infer that they wish to edit it, which requires the main option to be enabled; so why don't we save them some time and do that for them?

Using the Code

Integrating the code

The article code contains the CheckBoxPanel User Control, included in a simple VS2005 example application that demonstrates the Panel in operation. To use the panel in your own application, just copy CheckBoxPanel.cs and CheckBoxPanelDesigner.cs into your C# project and build it.

Using the panel in your own Forms

Now open your Form designer and in the toolbox you will find the CheckBoxPanel is listed at the top as a new type of control. Just drag it onto any Form and use it just like a GroupBox.

For it to operate, you must add at least one checkbox. This is the Master Control that will operate the panel. Just drag and drop a checkbox onto the Panel - any number of checkboxes can be added, but the nearest one to the top left corner of the Panel will be used as the Master Control by default.

Then add any additional controls that you wish to be disabled when the Master Control is unchecked.

That's all there is to it!

How it works

It's pretty simple really - The class is derived from Windows.Forms.Panel, which does almost all the work for us.

On initialisation, BindEvents() finds the Master Control and adds an event handler for CheckedChanged events on it. This will call the function mMasterControl_CheckedChanged if the user clicks the checkbox. When this happens, we enable/disable all the controls except the Master Control by looping through the Controls collection (A list of the child controls, provided by the Panel base-class). We just have to be careful not to disable the Master Control as well!

    void mMasterControl_CheckedChanged(object sender, EventArgs e)
    {
        if (mMasterControl == null)
            return;
        
        // Checked state has changed for the master checkbox.
        // Enable/disable all child items
        foreach (Control ctrl in Controls)
        {
            if (!ctrl.Equals(mMasterControl))
                ctrl.Enabled = mMasterControl.Checked;
        }
    }

We also want to enable the controls if the user clcks on any of them. CheckBoxPanel_Click reacts to clicks anywhere inside the Panel. We look to see if the click hits any child control using GetChildAtPoint on the current MousePosition - if it does, we set the Master Control checked and put the input focus into the clicked control. We don't have to update the controls explicitly because setting mMasterControl.Checked will automatically call our CheckedChanged event handler to enable all the controls again.

    void CheckBoxPanel_Click(object sender, EventArgs e)
    {
        if (mMasterControl != null && !mMasterControl.Checked)
        {
            Point pos = PointToClient(System.Windows.Forms.Control.MousePosition);
            Control child = GetChildAtPoint(pos, GetChildAtPointSkip.None);
            if (child != null)
            {
                mMasterControl.Checked = true;
                child.Focus();
            }
        }
    }

The remaining logic relates to Panels containing text boxes. If the input focus is lost, the Panel checks if it contains TextBox controls, and whether any of them have any text. If the user has deleted all the text from the text box(es), then the Master Control is unchecked to once again disable the controls.

First, this should only happen if the Panel only contains TextBoxes. In BindEvents() we loop through all the child controls to check that they are all TextBoxes:

    if (mAutoDisableBlankFields)
    {
        // See if this contains only text fields - if it does, when they are
        // all empty we untick the master control
        bool containsOnlyTextFields = true;
        foreach(Control ctrl in Controls)
        {
            if (ctrl is TextBox || (ctrl is CheckBox && ctrl.Equals(mMasterControl)))
            {
                // Ignore TextBoxes and the master control
            }
            else
            {
                containsOnlyTextFields = false;
                break;
            }
        }

... If this is true, we add our LostFocus event handler to each TextBox control:

        if (containsOnlyTextFields)
        {
            foreach(Control ctrl in Controls)
            {
                if (ctrl is TextBox)
                {
                    TextBox textCtrl = (TextBox) ctrl;
                    textCtrl.LostFocus += new EventHandler(TextCtrl_LostFocus);
                }
            }
        }
    }

Finally, TextCtrl_LostFocus checks if the focus has moved out of the Panel. In this case, it checks if all the text boxes are blank - if they are, then it sets mMasterControl.Checked = false to disable all the controls again.

    void TextCtrl_LostFocus(object sender, EventArgs e)
    {
        if (mMasterControl == null)
            return;
    
        foreach(Control ctrl in Controls)
        {
            TextBox textCtrl = ctrl as TextBox;
            if (textCtrl != null)
            {
                if (textCtrl.Focused ||                    // If the focus moved to
                                                           // another textbox in our
                                                           // panel, remain checked
                    !string.IsNullOrEmpty(textCtrl.Text))  // If a text box is non-empty,
                                                           // leave the option checked
                {
                    return;
                }
            }
        }

        // All text fields in the panel are blank, so we untick our checkbox
        mMasterControl.Checked = false;
    }

Options

The Panel provides the following properties (available from your code and in the Form designer) to further refine its behaviour:

  • MasterControl - If the default Master Control isn't as you wish, set the MasterControl to any CheckBox in the Panel.
  • AutoDisableBlankFields - If this property is true, and the user edits all the text fields within the Panel to be blank, the Panel contents will automatically be disabled.

Points of Interest

Good User Interface is all about attention to detail, streamlining user workflows to make it quick and easy to use an application, and adhering to intuitive standards to avoid confusing users. Even tiny features like those provided by the CheckBoxPanel can really improve the user experience.

Automating this type of UI enhancement also saves a lot of programmer time - you have the initial cost of developing a generic solution, but it pays back over the months and years as you find yourself re-using the same code to save time on every application you write.

History

18 August 2009 - Article first published

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Zot Williams
Technical Lead Atomineer
United Kingdom United Kingdom
Jason has been programming since 1981. He started off developing in BASIC and Assembler (Z80, 6502, ARM), and since then has primarily coded in Assembler, C, C++ and most recently C#, although he's dabbled in more languages than he can remember.
 
He spent many years authoring public domain applications and libraries in his spare time, but now spends most of his programming time on the Atomineer Pro Documentation add-in for Visual Studio.
Follow on   Twitter

Comments and Discussions

 
GeneralNormal Uses PinmemberPaul Selormey18-Aug-09 12:36 
AnswerRe: Normal Uses [modified] PinmemberZot Williams18-Aug-09 12:53 
AnswerRe: Normal Uses Pinmemberc-busse19-Aug-09 4:34 
GeneralRe: Normal Uses PinmemberZot Williams19-Aug-09 9:49 
GeneralRe: Normal Uses PinmemberAnt210024-Aug-09 8:39 
GeneralRe: Normal Uses PinmemberZot Williams24-Aug-09 10:39 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.141223.1 | Last Updated 18 Aug 2009
Article Copyright 2009 by Zot Williams
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid