Click here to Skip to main content
15,886,578 members
Articles / Desktop Programming / Windows Forms

UI State Synchronization of WinForm Controls

Rate me:
Please Sign up or sign in to vote.
4.50/5 (2 votes)
11 Oct 2011CPOL4 min read 18.2K   739   9  
UI State Synchronization of Win Form Controls

Introduction

I was developing a Windows Forms application during the last few months. In that application, I have multiple controls for performing a particular action. I need to show/hide, check/uncheck and enable/disable controls based on the action performed on the user control placed in the form. I was facing the problem that I need to set the state of all controls for particular action and if we forgot to update state of any control, the inconsistent state of controls will be left behind.

Background

I will describe this article with the help of an example. We have a user control that is composed in a form. We are taking GridView in user control that will be displaying some records. The record can be updated by selecting grid row and perform Edit action either of the three ways:

  1. Edit button
  2. Edit toolbar button
  3. Edit context menu

These action controls should be enabled only when the record is selected. There are several ways to accomplish this activity, but every approach has some cost. We can expose events in user control for row selection/deselection and set state of action controls on the form. Here the important point is that you need to set state of all the controls for a particular action. But according to my framework, you do not need to set properties of user controls on the row selection and deselection.

How It Works?

The framework works in the following way:

  1. Define command constants in user control.
  2. Add commands in form constructor with the control references. If there is more than one control to perform an action, add command for every control.
  3. UpdateCommand on the row selection event in user control.

Using the Code

There are two main classes for state handling framework:

  1. StateManager
  2. UiObject
  3. UIStates enum

UiObject

This object will wrap Windows Form controls. It is used to make the object symmetrical. This is a sealed class and its object cannot be created directly. A static method CreateObject(object o) is exposed that will take windows form control (Button, ContextMenuItem,ToolbarButton,...) and return instance of UiObject. This should be the only public method in this class.

C#
public static UIObject CreateObject(object o)
        {
            Control ctrl = o as Control;

            if (ctrl== null)
            {
                Component cmp = o as Component;

                if (cmp == null)
                {
                    throw new Exception("Invalid control");
                }
            }

            UIObject obj = new UIObject(o);
            return obj;
        }

The 'o' parameter should be cast in Control object. Here we are using win controls therefore we have cast parameter into base class of all the Controls/Components. If you are writing this framework for third party controls, use the base control class of those third party controls.

C#
internal void SetCommandStatus(UIStates state)
{
	switch (state)
    {
		case UIStates.Visible:
			this.SetControlVisibility(true);
            break;

		case UIStates.InVisible:
			this.SetControlVisibility(false);
            break;

		case UIStates.Enabled:
			this.SetControlActiveState(true);
			break;

		case UIStates.Disabled:
			this.SetControlActiveState(false);
			break;

		case UIStates.Checked:
			this.SetControlCheckState(true);
			break;

		case UIStates.UnChecked:
			this.SetControlCheckState(false);
			break;
	}
}

private void SetControlCheckState(bool flag)
{
	if (this.mUiObject is RadioButton)
	{
		((RadioButton)this.mUiObject).Checked = flag;
	}
    else if (this.mUiObject is CheckBox)
	{
		((CheckBox)this.mUiObject).Checked = flag;
	}
	else if (this.mUiObject is MenuItem)
	{
		((MenuItem)this.mUiObject).Checked = flag;
	}
    else if (this.mUiObject is ToolStripMenuItem)
    {
		((ToolStripMenuItem)this.mUiObject).Checked = flag;
	}
}

private void SetControlVisibility(bool flag)
{
	if (this.mUiObject is ButtonBase)
	{
		((ButtonBase)this.mUiObject).Visible = flag;
	}
	else if (this.mUiObject is MenuItem)
	{
		((MenuItem)this.mUiObject).Visible = flag;
	}
	else if (this.mUiObject is ToolStripItem)
	{
		((ToolStripItem)this.mUiObject).Visible = flag;
	}
}

private void SetControlActiveState(bool flag)
{
    if (this.mUiObject is ButtonBase)
    {
        ((ButtonBase)this.mUiObject).Enabled = flag;
    }
	else if (this.mUiObject is MenuItem)
	{
		((MenuItem)this.mUiObject).Enabled = flag;
	}
	else if (this.mUiObject is ToolStripItem)
	{
		((ToolStripItem)this.mUiObject).Enabled = flag;
	}
}

The SetCommandStatus method will set the state of the User interface controls. The access specifier of this method is 'internal' because it is intended to call from 'Statemanager' class only. The UIStates parameter will let this method set the object state. The other methods are user as helper methods.

StateManager

It contains a dictionary of string commands and UIObjects lists. This object is responsible for the following:

  1. Subscribe action commands and winform controls.
  2. Set the status of subscribed commands.
C#
public void AddCommand(string command, UIObject uiObject)
{
	List<uiobject> uiObjects = null;
	//Check whether the action is already added or not
	if (this.mUiObjectsMapping.ContainsKey(command)) //If it is already added
	{
		//Retrieve UIObject List
		uiObjects = this.mUiObjectsMapping[command];
		//Add UIObject into list
		uiObjects.Add(uiObject);
	}
	else //If it is not in the list
	{
		//Create new UIObject list
		uiObjects = new List<uiobject>();
		uiObjects.Add(uiObject);
		this.mUiObjectsMapping.Add(command, uiObjects); //Add object list 
							//against UICommand
	}
}

This method will map action command against UIObject list.

UIStates Enum

This enum will contain winform control states:

  1. Visible: The control will be displayed on the form.
  2. InVisible: The control will be hidden on the form.
  3. Enabled: The control will be visible and active for action.
  4. Disabled: The control will be visible and inactive for action.
  5. Checked: The control will be checked.
  6. UnChecked: The control will be un-checked.

Sample Client Code

I have implemented this framework in the sample application. This TestForm will compose TestUC. There is a button for record updation. We can execute edit command in by clicking on Edit button, Edit context menu or from toolbar button. The state handling of these three controls can be controlled by this framework. You do not need to write enable/disable code for all these controls again and again. Just register commands and call UpdateCommandStatus on row selection event.

You need to perform the following actions for plugging this code into your application:

  1. Create instance level object of StateManger in UserControl.
  2. Write AddComand(String cmd, UIObject o) in UserControl for subscribing commands.
  3. Add UpdateCommandStatus() in user control and write here when to enable / disable controls.
  4. Call UpdateCommandStatus() on appropriate event, in my example I have called it on SelectionChangedEvent.You can call this method either from user control or from WinForm or both, depends on the requirement.
  5. Register commands in WinForm constructor. As discussed earlier for multiple controls, we need to register commands multiple times with each control reference.
    C#
    this.testUC1.AddCommand(TestUC.COMMAND_ENABLE_BUTTON, 
    			UIObject.CreateObject(this.btnEdit));
    this.testUC1.AddCommand(TestUC.COMMAND_ENABLE_BUTTON, 
    			UIObject.CreateObject(this.toolStripBtnEdit));
    this.testUC1.AddCommand(TestUC.COMMAND_ENABLE_BUTTON, 
    			UIObject.CreateObject(this.editToolStripMenuItem));

I have added Clear Selection button for demo purposes. The controls will be enabled on row selection and disabled when there is no row selected.

Points of Interest

This approach involves one time cost only. The maintenance and implementation cost of this framework is very low and you will learn how to synchronize controls state in a concentric fashion.

History

  • 9th October, 2011: Initial version

License

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


Written By
Web Developer
Pakistan Pakistan
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
-- There are no messages in this forum --