Windows 窗体设置保存程序






4.28/5 (6投票s)
2005 年 4 月 27 日
3分钟阅读

40930

1044
介绍了一种使用 XML 保存和重新加载 Form 控件状态的通用方法。
引言
在开发 GUI 时,例如为新的硬件创建原型,通常会有大量的复选框、列表框、单选按钮、文本框等等。这些控件经常被添加到窗体中或从窗体中移除,因为它们的作用仅仅是支持测试和开发的需求。在每次运行之间,组件的状态(是否选中、值、索引等)必须重新输入。如果能够实现一种通用的保存各种组件状态的方法,而无需为 GUI 功能的每次更改而进行修改,这将非常方便。本文概述了一种通过以通用方式将设置信息保存到 XML 来实现这一目标的方法。
使用代码
在 Visual Studio .NET 中打开 TestForm 解决方案文件。可下载的代码包括 FormSetupSaver 类项目和一个简单的 GUI 应用程序项目来测试该类。FormSetupSaver
类有一个构造函数,它接受 Form
的 Controls
作为参数。
FormSetupSaver setupSaver = new FormSetupSaver(this.Controls);
该类有两个方法:Save
和 Load
,每个方法都接受 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
' 关键字检查每个控件的类型。根据类型以及我们是否支持它(在此示例中仅支持 TextBox
和 CheckBox
,但在源代码中还有其他类型),将详细信息写入 XML 文件。使用 XmlTextWriter
,我们将类型写入为一个元素,并将名称作为第一个属性。所有组件都相同。但是,正如在示例中可以看到的那样,CheckBox
和 TextBox
具有不同的属性:布尔值 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;
}