65.9K
CodeProject 正在变化。 阅读更多。
Home

Windows 窗体设置保存程序

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.28/5 (6投票s)

2005 年 4 月 27 日

3分钟阅读

viewsIcon

40930

downloadIcon

1044

介绍了一种使用 XML 保存和重新加载 Form 控件状态的通用方法。

Sample Image

引言

在开发 GUI 时,例如为新的硬件创建原型,通常会有大量的复选框、列表框、单选按钮、文本框等等。这些控件经常被添加到窗体中或从窗体中移除,因为它们的作用仅仅是支持测试和开发的需求。在每次运行之间,组件的状态(是否选中、值、索引等)必须重新输入。如果能够实现一种通用的保存各种组件状态的方法,而无需为 GUI 功能的每次更改而进行修改,这将非常方便。本文概述了一种通过以通用方式将设置信息保存到 XML 来实现这一目标的方法。

使用代码

在 Visual Studio .NET 中打开 TestForm 解决方案文件。可下载的代码包括 FormSetupSaver 类项目和一个简单的 GUI 应用程序项目来测试该类。FormSetupSaver 类有一个构造函数,它接受 FormControls 作为参数。

 FormSetupSaver setupSaver = new FormSetupSaver(this.Controls);

该类有两个方法:SaveLoad,每个方法都接受 XML 文件的名称,用于存储详细信息。不要将 .xml 扩展名添加到文件名变量中。

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

尝试添加和删除复选框、列表框、单选按钮和文本框。

将控件状态写入 XML 文件

主要工作是在 FormSetupSaver 类的两个私有方法中完成(参见源文件 FormSetupSaver.cs)。这些方法是 WriteCycleThroughControls(由 Save 方法使用)和 ReadCycleThroughControls(由 Load 方法使用)。首先,这是一个精简版的 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);
         }
     }
 }

我们遍历所有控件,并使用 'is' 关键字检查每个控件的类型。根据类型以及我们是否支持它(在此示例中仅支持 TextBoxCheckBox,但在源代码中还有其他类型),将详细信息写入 XML 文件。使用 XmlTextWriter,我们将类型写入为一个元素,并将名称作为第一个属性。所有组件都相同。但是,正如在示例中可以看到的那样,CheckBoxTextBox 具有不同的属性:布尔值 Checked 和字符串 Text 分别。写入一个 end 元素以完成当前控件的信息。

最令人感兴趣的是如何处理容器控件(如 GroupBox)内的控件。这些控件不会在 Form 自身的 Controls 列表中看到。因此,当我们遇到 GroupBox 时,我们会递归地再次调用 WriteCycleThroughControls。这样,我们就可以透明地处理嵌套在 GroupBox 或其他容器中的 GroupBox (如果它们存在的话)。

读取 XML 文件并更新控件

这稍微复杂一些。我们设置一个 XmlTextReader 并使用一个 while 循环来遍历 XML 文件。如果找到一个元素,那么我们检查它是否是一个有效的控件。一个简单的检查方法是查看控件类型的名称是否以预期的方式开头("System.Windows.Forms")。如果是,则获取属性。另一个名为 GetControl 的私有方法执行通过遍历所有控件(包括控件内的控件)来获取实际控件的工作(递归调用 GetControl)。如果 XML 文件中找到的控件名称与控件列表中的控件名称匹配,那么我们已经找到了正确的控件并返回它。如果找不到它(例如,我们删除了一个现在不必要的 TextBox),那么将返回一个空指针,我们无害地跳到 XML 文件中的下一个元素。

最后,根据控件的类型,我们设置正确的属性(.Text 用于 TextBox.Checked 用于 CheckBox)。

 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;
 }
© . All rights reserved.