简介
保存应用程序设置是一项常见任务。过去,我们通常将设置保存到 INI 文件或注册表中。而在 Microsoft® .NET 框架中,我们多了另一种选择,即将应用程序设置序列化到 XML 文件中,以便轻松地更新和检索这些设置。Microsoft Visual Studio® .NET 使用 System.Configuration.AppSettingsReader 类读取存储在配置文件中的 DynamicProperties。但是,这些动态属性在运行时是只读的,因此您无法保留用户所做的更改。本文将介绍如何序列化数据并将其写入一个文件,以及如何读取和反序列化该数据。存储数据的方式和位置取决于要存储的内容,本文将讨论如何根据数据类型将其存储到相应的位置。
保存应用程序设置的前提
Windows 窗体 Application 类包含多个属性,答应您轻松导航到注册表或用户数据文件夹的相应部分。要正确使用这些属性,您必须设置 AssemblyCompany、AssemblyProdUCt 和 AssemblyVersion 属性。
这些属性设置的值由 Control 类通过 CompanyName、ProductName 和 ProductVersion 属性公开。
下面是一个简单的 Windows 窗体示例,其中设置了程序集属性并将其显示在 Label 中:
' Visual Basic
Imports System
Imports System.Windows.Forms
Imports System.Reflection
' 设置程序集属性。
Public Class AboutDialogBox
Inherits Form
Public Sub New()
' 在 Label 中显示程序集信息。
Dim label1 As New Label()
label1.Text = _
Me.CompanyName + " " + _
Me.ProductName + " 版本: " + _
Me.ProductVersion
label1.AutoSize = True
Me.Controls.Add(label1)
End Sub
End Class
//C#
using System;
using System.Windows.Forms;
using System.Reflection;
// 设置程序集属性。
[assembly: AssemblyCompany("Microsoft")]
[assembly: AssemblyProduct("MyApplication")]
[assembly: AssemblyVersion("1.0.1")]
public class AboutDialogBox : Form
{
public AboutDialogBox()
{
// 在 Label 中显示程序集信息。
Label label1 = new Label();
label1.Text = this.CompanyName + " "
+ this.ProductName + " 版本: "
+ this.ProductVersion;
label1.AutoSize = true;
this.Controls.Add(label1);
}
[STAThread]
static void Main()
{
Application.Run(new AboutDialogBox());
}
}
使用注册表存储数据
假如数据对应用程序而言非常敏感或十分重要,您可能不希望只简单地序列化数据;因为假如这样,任何人都可以使用文本编辑器查看或编辑这些数据;而注册表可以限制对数据的访问。注册表为应用程序和用户设置提供了强大的存储能力。多数备份程序会自动备份注册表设置。当您将信息放到注册表中的正确位置后,在存储设置时可自动避开用户。虽然用户可以编辑注册表,但他们通常不会这样做,这便使得您的设置更加稳定。总之,只要遵守使用注册表的 Microsoft Windows® 徽标原则,注册表将是存储应用程序设置的理想位置。
要写入注册表,您的应用程序需要 Create 和 Write 注册表权限;要读取注册表,则需要 Read 权限。有关使用注册表项的具体信息,请参阅 .NET 框架 SDK 文档中有关 Microsoft.Win32.RegistryKey 类的 GetValue 和 SetValue 方法的文档以及 System.Security.Permissions.RegistryPermissionAccess 枚举文档。
要将信息保存到注册表,请使用 Application 类的 UserAppDataRegistry 或 CommonAppDataRegistry 属性。这些属性将根据用户类型返回一个可用于存储应用程序数据的 RegistryKey 对象:
UserAppDataRegistry 属性返回的注册表项可用于存储每个用户的漫游数据(与计算机无关的特定用户设置);注册表项的形式为 HKEY_CURRENT_USER\Software\[Control.CompanyName]\[Control.ProductName]\[Control.ProductVersion]。
CommonAppDataRegistry 属性返回的注册表项可用于存储计算机的非特定用户的、非漫游数据;注册表项的形式为 HKEY_LOCAL_MACHINE\Software\[Control.CompanyName]\[Control.ProductName]\[Control.ProductVersion]。
这两种属性都是只读属性,它们返回的 RegistryKey 对象具有多种方法,可用于读取、更新或创建注册表项和值。
将数据保存到注册表
下面的示例在关闭窗体时,假如连接字符串被更改,则将连接字符串保存到注册表中。
' Visual Basic
Private appSettingsChanged As Boolean
Private connectionString As String
Private Sub Form1_Closing(sender As Object,
e As CancelEventArgs) Handles MyBase.Closing
If appSettingsChanged Then
Try
' 假如连接字符串已更改,则将其保存到注册表中。
Application.UserAppDataRegistry.SetValue("ConnString", _
connectionString)
Catch ex As Exception
MessageBox.Show(ex.Message )
End Try
End If
End Sub
// C#
private bool appSettingsChanged;
private string connectionString;
private void Form1_Closing(object sender, CancelEventArgs e)
{
if(appSettingsChanged)
{
try
{
// 假如连接字符串已更改,则将其保存到注册表中。
Application.UserAppDataRegistry.SetValue("ConnString",
connectionString);
}
catch(Exception ex)
{
MessageBox.Show(ex.Message );
}
}
}
从注册表检索数据
下面的示例在加载窗体时,从注册表中检索连接字符串。
' Visual Basic
Private appSettingsChanged As Boolean
Private connectionString As String
Private Sub Form1_Load(sender As Object,
e As EventArgs) Handles MyBase.Load
Try
' 从注册表中获取连接字符串。
If Not (Application.UserAppDataRegistry.GetValue("ConnString") _
Is Nothing) Then
connectionString = _
Application.UserAppDataRegistry.GetValue( _
"ConnString").ToString()
statusBar1.Text = "连接字符串: " + connectionString
End If
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
End Sub
// C#
private bool appSettingsChanged;
private string connectionString;
private void Form1_Load(object sender, EventArgs e)
{
try
{
// 从注册表中获取连接字符串。
if(Application.UserAppDataRegistry.GetValue("ConnString") != null)
{
connectionString =
Application.UserAppDataRegistry.GetValue(
"ConnString").ToString();
statusBar1.Text = "连接字符串: " +
connectionString;
}
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
创建自定义应用程序配置类
本文介绍的应用程序配置类将其实例序列化为 XML。序列化是将对象或对象图转换为线性字节序列以便存储或传输到其他位置的过程。反序列化是接收所存储或传输的信息并从中重新创建对象的过程。您可以将对象序列化为文本(XML 是具有分层结构的文本)或二进制格式。有关序列化的具体信息,请参阅 .NET 框架开发人员指南中的 Serializing Objects。
从 Control 派生出来的 Windows 窗体类不能轻易序列化为 XML,因为它们包含具有动态状态(例如窗口句柄 [HWND])的对象。由于不能轻易完全序列化控件,并且通常并不需要保留由控件公开的每个属性,因此应当创建一个小型的、可序列化为 XML 的类来存储所需要的属性值。例如,您可能只需要存储窗体的 BackColor、用户保存文件的最后一个目录或上次关闭窗体时窗体的 Location。要写入或创建 XML 文件,您的应用程序需要 Write 权限;要读取 XML 文件,则需要 Read 权限。有关具体信息,请参阅 .NET 框架 SDK 中有关 StreamWriter 构造函数的文档以及 System.Security.Permissions.FileIOPermissionAccess 枚举文档。某些类型需要先经过转换,然后才能序列化为 XML。例如,要将 System.Drawing.Color 序列化为 XML,必须先使用 ToArgb 方法将其转换为整数。类型转换器也可用于将类型转换为字符串表示。有关类型转换器的具体信息,请参阅 .NET 框架 SDK 文档中的 TypeConverter 类文档和 Implementing a Type Converter。
Application 类中的几个属性提供了可用于存储应用程序数据的应用程序存储路径:
UserAppDataPath 属性用于存储每个用户的漫游数据(与计算机无关的特定用户设置);路径的形式为 [UserName]\Application Data\[Control.CompanyName]\[Control.ProductName]\[Control.Produc