Click here to Skip to main content
15,867,453 members
Articles / Database Development / SQL Server
Article

Windows Forms Setup Saver

Rate me:
Please Sign up or sign in to vote.
4.28/5 (6 votes)
26 Apr 20053 min read 39.5K   1K   37   4
Presents a generic method of saving and reloading the status of a Form's controls using XML.

Sample Image

Introduction

When developing GUIs, say for prototyping new hardware, it is quite common to have a wide selection of check boxes, list boxes, radio buttons, text boxes, etc. These are often added and removed from the form quite regularly, as their role is simply to support testing and development needs. Between runs, the status of the components (checked or not, values, indexes, etc.) must be re-entered. It would be convenient if a generic way of saving the status of the various components could be implemented that does not need altering for each change in the GUI features. This article outlines a means of achieving this, by generically saving set-up information to XML.

Using the code

Open the TestForm solution file in Visual Studio .NET. The downloadable code consists of the FormSetupSaver class project and a simple GUI application project to test the class. The FormSetupSaver class has a constructor that takes the Form's Controls as an argument.

C#
FormSetupSaver setupSaver = new FormSetupSaver(this.Controls);

The class has two methods: Save and Load, each taking the name of the XML file where the details will be stored. Don't add the .xml extension to the filename variable.

C#
setupSaver.Save(filename);
setupSaver.Load(filename);

Try adding and removing check boxes, list boxes, radio buttons, and text boxes.

Writing the control status to XML file

The body of the work is done in two private methods of the FormSetupSaver class (see source file FormSetupSaver.cs). These methods are WriteCycleThroughControls (used by Save method) and ReadCycleThroughControls (used by Load method). First, here is a stripped down version of WriteCycleThroughControls:

C#
private void WriteCycleThroughControls(XmlTextWriter xw,
                          Control.ControlCollection controls)
{
    foreach(Control c in controls)
    {
        if(c is TextBox)
        {
            xw.WriteStartElement(c.GetType().ToString());
            xw.WriteAttributeString("Name", c.Name);
            xw.WriteAttributeString("Text", c.Text);
            xw.WriteEndElement();
        }
        else if(c is CheckBox)
        {
            xw.WriteStartElement(c.GetType().ToString());
            xw.WriteAttributeString("Name", c.Name);
            xw.WriteAttributeString("Checked",
                       ((CheckBox)c).Checked.ToString());
            xw.WriteEndElement();
        }
        //else etc etc

        else if(c is GroupBox)
        {
            WriteCycleThroughControls(xw, c.Controls);
        }
    }
}

We cycle through all the controls and check the type of each using the 'is' keyword. Depending on the type and whether we support it (in this example only TextBoxes and CheckBoxes are, but in the source code there are others), the details are written to an XML file. Using an XmlTextWriter, we write the type as an element, and the name as the first attribute. This the same for all components. However, as can be seen in the example, CheckBoxes and TextBoxes have different properties: boolean Checked and string Text respectively. Write an end element to complete information for the current control.

Of greatest interest is how to handle controls that are within container controls, such as GroupBoxes. These will not be seen within the Form's own Controls list. Therefore, we recursively call WriteCycleThroughControls again when we hit a GroupBox. This way we can transparently handle GroupBoxes nested within GroupBoxes or other containers (if they are present).

Reading the XML file and updating the controls

This is slightly more complex. We set up an XmlTextReader and use a while loop to go through the XML file. If an element is found then we check whether it is a valid control. A simple check is to see if the name of the control type begins in an expected manner ("System.Windows.Forms"). If so then get the attributes. Another private method called GetControl does the work to get the actual control by cycling through all the controls including controls within controls (recursive calling of GetControl). If the control name found in the XML file matches the name of the control in the controls list then we've found the right control and return it. If it can't be found (say, we deleted a now unnecessary TextBox) then a null pointer is returned and we harmlessly skip to the next element in the XML file.

Finally, depending on the type of control, we set the correct property (.Text for TextBoxes, .Checked for CheckBoxes).

C#
private void ReadCycleThroughControls(XmlTextReader xr,
                                       Control.ControlCollection controls)
{
    string controltype;
    string controlname;
    string controlvalue;
    int index=0;
    Control c = null;
    while(xr.Read())
    {
        if(xr.NodeType == XmlNodeType.Element || xr.IsEmptyElement == false)
        {
            controltype = xr.Name;
            // Check we do have a valid control. If so get the name and value.
            if(controltype.StartsWith("System.Windows.Forms"))
            {
                xr.MoveToNextAttribute();
                controlname = xr.Value;
                xr.MoveToNextAttribute();
                controlvalue = xr.Value;
            }
            else
                continue;

            // set local control to null
            c = null;

            // check control type is valid string and then get the control
            if(controltype.Length > 0)
                c = GetControl(controlname, controls);

            // move back to the element
            xr.MoveToElement();

            // if GetControl returns null then control was not found, so skip
            if(c == null)
                continue;

            // Set the control according to type
            if(c is TextBox)
                ((TextBox)c).Text = controlvalue;
            else if(c is CheckBox)
                ((CheckBox)c).Checked = Convert.ToBoolean(controlvalue);
            // else
        }
    }
}

private Control GetControl(string controlname, Control.ControlCollection controls)
{
    Control controlInGroupBox = null;
    foreach(Control c in controls)
    {
        if(c is GroupBox)
        {
            controlInGroupBox = GetControl(controlname, c.Controls);
            if(controlInGroupBox != null)
                return controlInGroupBox;
        }
        else if(c.Name == controlname)
        {
            return c;
        }
    }
    return null;
}

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Systems Engineer Hybrid DSP Systems
Netherlands Netherlands
Nick is co owner of Hybrid DSP, a company specialized in high speed data acquisition, processing and storage.

CUDAfy.NET took considerable effort to develop and we ask nothing in return from users of the LGPL library other than that you please consider donating to Harmony through Education. This small charity helps handicapped children in developing countries by providing suitable schooling.

Comments and Discussions

 
GeneralTabControl Pin
Patrik Ruzic23-Jun-05 21:50
Patrik Ruzic23-Jun-05 21:50 
GeneralAnd even one more... Pin
Robert Rohde27-Apr-05 20:13
Robert Rohde27-Apr-05 20:13 
GeneralYet more alternatives Pin
Marc Clifton27-Apr-05 10:37
mvaMarc Clifton27-Apr-05 10:37 
GeneralAnother way to do this Pin
Steven Campbell27-Apr-05 3:08
Steven Campbell27-Apr-05 3:08 
Rather than code specifically for checkboxes or textboxes, your could use some of the built-in reflective capabilities of .NET. For example:
TypeDescriptor.GetProperties(myControl) will return a list of property descriptors for the control. This is the same thing that VS.NET uses to be able to display the property grid.
Once you have a collection of PropertyDescriptor objects, you can then iterate through them. If myPropertyDescriptor.ShouldSerializeValue(myControl) = true then that means that the value of the property is different from its default, and can be persisted. You could then serialize the property to XML. Again, pretty much what VS.NET does when using the forms designer.


my blog

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

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