Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Windows Forms Setup Saver

0.00/5 (No votes)
26 Apr 2005 1  
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.

 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