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

Windows Forms Setup Saver

By , 26 Apr 2005
Rate this:
Please Sign up or sign in to vote.

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.

 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.

 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:

 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).

 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

About the Author

Nick Kopp
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.
Follow on   Twitter

Comments and Discussions

 
GeneralTabControl PinmemberPatrik Ružič23-Jun-05 21:50 
GeneralAnd even one more... PinmemberRobert Rohde27-Apr-05 20:13 
GeneralYet more alternatives PinprotectorMarc Clifton27-Apr-05 10:37 
GeneralAnother way to do this PinmemberSteven Campbell27-Apr-05 3:08 

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 | Mobile
Web04 | 2.8.140415.2 | Last Updated 27 Apr 2005
Article Copyright 2005 by Nick Kopp
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid