在 .NET 框架中保留应用程序设置
Jeff Danner
Microsoft Corporation
2002 年 6 月
摘要:本文介绍在 Microsoft .NET 框架中,如何通过将应用程序设置保存到注册表中或将其序列化到配置文件中,在运行时保留应用程序设置。本文包含一些指向英文站点的链接。
目录
简介
保存应用程序设置的前提
使用注册表存储数据
将数据保存到注册表
从注册表检索数据
创建自定义应用程序配置类
将应用程序设置类用于应用程序
加载保存的应用程序设置
保存应用程序设置
小结
简介
保存应用程序设置是一项常见任务。过去,我们通常将设置保存到 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 ' 设置程序集属性。 <Assembly: AssemblyCompany("Microsoft")> <Assembly: AssemblyProduct("MyApplication")> <Assembly: AssemblyVersion("1.0.1")> 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.ProductVersion]。
- LocalUserAppDataPath 属性用于存储每个用户的非漫游数据;路径的形式为 [UserName]/Local Settings/Application Data/[Control.CompanyName]/[Control.ProductName]/[Control.ProductVersion]。
- CommonAppDataPath 属性用于存储计算机的非用户特定的、非漫游数据;路径的形式为 All Users/Application Data/[Control.CompanyName]/[Control.ProductName]/[Control.ProductVersion]。
注意:
数据路径中使用的
UserName 值是从
System.Environment 类的
UserName 属性检索而来的。
通常,漫游存储只能容纳较小的数据(如窗体设置),而非漫游存储可以容纳较大的数据(如大型位图的缓存)。
下面的示例包含一个存储应用程序设置的类。该类提供了用于加载(反序列化)和保存(序列化)应用程序设置的 LoadAppSettings 和 SaveAppSettings 方法。BackColor 属性值存储为整数,因此可以被序列化。该示例将序列化的数据保存到名为 MyApplication.config 的文件中。请注意,该文件不同于 Visual Studio .NET 所使用的 App.config 文件。
- 创建类并添加表明应用程序设置是否已更改的布尔型变量。确保添加对 System.Xml.Serialization 和 System.IO 命名空间的引用,并添加对可能需要用来存储数据的任何其他命名空间的引用。
' Visual Basic Imports System Imports System.Xml.Serialization Imports System.IO Imports System.Drawing Namespace Samples Public Class ApplicationSettings Private appSettingsChanged As Boolean End Class End Namespace // C# using System; using System.Xml.Serialization; using System.IO; using System.Drawing; namespace Samples { public class ApplicationSettings { private bool appSettingsChanged; } }
- 添加私有变量以存储应用程序设置,并创建公共属性访问这些变量。
' Visual Basic ' 用于存储应用程序设置的变量。 Private m_defaultDirectory As String Private m_backColor As Integer Private m_formLocation As Point ' 用于访问应用程序设置变量的属性。 Public Property DefaultDirectory() As String Get Return m_defaultDirectory End Get Set If value <> m_defaultDirectory Then m_defaultDirectory = value appSettingsChanged = True End If End Set End Property Public Property BackColor() As Integer Get Return m_backColor End Get Set If value <> m_backColor Then m_backColor = value appSettingsChanged = True End If End Set End Property Public Property FormLocation() As Point Get Return m_formLocation End Get Set If Not value.Equals(m_formLocation) Then m_formLocation = value appSettingsChanged = True End If End Set End Property // C# // 用于存储应用程序设置的变量。 private string m_defaultDirectory; private int m_backColor; private Point m_formLocation; // 用于访问应用程序设置变量的属性。 public string DefaultDirectory { get{return m_defaultDirectory;} set { if(value != m_defaultDirectory) { m_defaultDirectory = value; appSettingsChanged = true; } } } public int BackColor { get{return m_backColor;} set { if(value != m_backColor) { m_backColor = value; appSettingsChanged = true; } } } public Point FormLocation { get{return m_formLocation;} set { if(value != m_formLocation) { m_formLocation = value; appSettingsChanged = true; } } }
- 添加方法以序列化应用程序设置并将其保存到配置文件。
' Visual Basic ' 如果设置发生变化,则将 ' 类序列化到配置文件中。 Public Function SaveAppSettings() As Boolean If Me.appSettingsChanged Then Dim myWriter As StreamWriter = Nothing Dim mySerializer As XmlSerializer = Nothing Try ' 为 ApplicationSettings 类型 ' 创建 XmlSerializer。 mySerializer = New XmlSerializer( _ GetType(ApplicationSettings)) myWriter = New StreamWriter( _ Application.LocalUserAppDataPath + _ "/myApplication.config", False) ' 将 ApplicationSettings 类的这一实例 ' 序列化到配置文件中。 mySerializer.Serialize(myWriter, Me) Catch ex As Exception MessageBox.Show(ex.Message) Finally ' 如果 FileStream 是打开的,将其关闭。 If Not (myWriter Is Nothing) Then myWriter.Close() End If End Try End If Return appSettingsChanged End Function // C# // 如果设置发生变化,则将 // 类序列化到配置文件中。 public bool SaveAppSettings() { if(this.appSettingsChanged) { StreamWriter myWriter = null; XmlSerializer mySerializer = null; try { // 为 ApplicationSettings 类型 // 创建 XmlSerializer。 mySerializer = new XmlSerializer( typeof(ApplicationSettings)); myWriter = new StreamWriter(Application.LocalUserAppDataPath + @"/myApplication.config",false); // 将 ApplicationSettings 类的这一实例 // 序列化到配置文件中。 mySerializer.Serialize(myWriter, this); } catch(Exception ex) { MessageBox.Show(ex.Message); } finally { // 如果 FileStream 是打开的,将其关闭。 if(myWriter != null) { myWriter.Close(); } } } return appSettingsChanged; }
- 添加方法以从配置文件中反序列化应用程序设置。
' Visual Basic ' 从配置文件中反序列化类。 Public Function LoadAppSettings() As Boolean Dim mySerializer As XmlSerializer = Nothing Dim myFileStream As FileStream = Nothing Dim fileExists As Boolean = False Try ' 为 ApplicationSettings 类型创建 XmlSerializer。 mySerializer = New XmlSerializer(GetType(ApplicationSettings)) Dim fi As New FileInfo(Application.LocalUserAppDataPath + _ "/myApplication.config") ' 如果配置文件存在,将其打开。 If fi.Exists Then myFileStream = fi.OpenRead() ' 反序列化配置文件以创建新的 ' ApplicationSettings 实例。 Dim myAppSettings As ApplicationSettings = CType( _ mySerializer.Deserialize(myFileStream), _ ApplicationSettings) ' 为 ApplicationSettings 类的这一实例 ' 分配属性值。 Me.m_backColor = myAppSettings.BackColor Me.m_formLocation = myAppSettings.FormLocation Me.m_defaultDirectory = myAppSettings.DefaultDirectory fileExists = True End If Catch ex As Exception MessageBox.Show(ex.Message) Finally ' 如果 FileStream 是打开的,将其关闭。 If Not (myFileStream Is Nothing) Then myFileStream.Close() End If End Try ' 如果没有设置 myDirectory,则默认为 ' 用户的“我的文档”目录。 If m_defaultDirectory Is Nothing Then m_defaultDirectory = Environment.GetFolderPath( _ System.Environment.SpecialFolder.Personal) Me.appSettingsChanged = True End If Return fileExists End Function // C# // 从配置文件中反序列化类。 public bool LoadAppSettings() { XmlSerializer mySerializer = null; FileStream myFileStream = null; bool fileExists = false; try { // 为 ApplicationSettings 类型创建 XmlSerializer。 mySerializer = new XmlSerializer(typeof(ApplicationSettings)); FileInfo fi = new FileInfo(Application.LocalUserAppDataPath + @"/myApplication.config"); // 如果配置文件存在,将其打开。 if(fi.Exists) { myFileStream = fi.OpenRead(); // 反序列化配置文件以创建新的 // ApplicationSettings 实例。 ApplicationSettings myAppSettings = (ApplicationSettings)mySerializer.Deserialize( myFileStream); // 为 ApplicationSettings 类的这一实例 // 分配属性值。 this.m_backColor = myAppSettings.BackColor; this.m_formLocation = myAppSettings.FormLocation; this.m_defaultDirectory = myAppSettings.DefaultDirectory; fileExists = true; } } catch(Exception ex) { MessageBox.Show(ex.Message); } finally { // 如果 FileStream 是打开的,将其关闭。 if(myFileStream != null) { myFileStream.Close(); } } if(m_defaultDirectory == null) { // 如果没有设置 myDirectory,则默认为 // 用户的“我的文档”目录。 m_defaultDirectory = Environment.GetFolderPath( System.Environment.SpecialFolder.Personal); this.appSettingsChanged = true; } return fileExists; }
将应用程序设置类用于应用程序
您只需在应用程序中添加几行代码,便可以使用应用程序设置类对要保留的值进行序列化和反序列化。
加载保存的应用程序设置
您必须有一个变量具有可用于保存应用程序设置的类型;在此示例中,是一个名为
applicationSettings 的 ApplicationSettings 类。在代码的适当位置调用反序列化数据的方法;在此示例中,该方法名为 LoadAppSettings(),在窗体的 Load 事件中调用。您可以在任何其他初始化代码后面的构造函数中调用此方法,也可以在 Load 事件处理程序中调用。然后,将存储的值分配给应用程序的相应属性。
下面的示例在窗体的 Load 事件中加载应用程序设置,并将值分配给相应的属性。此示例假设窗体有一个名为 defaultDirectory 的变量。
' Visual Basic ' 如果 LoadAppSettings 方法成功,则将 ApplicationSettings ' 属性分配给相应的窗体属性。 Private Sub Form1_Load(sender As Object, _ e As EventArgs) Handles MyBase.Load If applicationSettings.LoadAppSettings() Then ' 从整数 (ARGB) 值中创建 Color。 Me.BackColor = Color.FromArgb(applicationSettings.BackColor) Me.Location = applicationSettings.FormLocation Me.defaultDirectory = applicationSettings.DefaultDirectory End If End Sub // C# // 如果 LoadAppSettings 方法成功,则将 ApplicationSettings // 属性分配给相应的窗体属性。 private void Form1_Load(object sender, EventArgs e) { if(this.applicationSettings.LoadAppSettings() ) { // 从整数 (ARGB) 值中创建 Color。 this.BackColor = Color.FromArgb(applicationSettings.BackColor); this.Location = applicationSettings.FormLocation; this.defaultDirectory = applicationSettings.DefaultDirectory; } }
保存应用程序设置
您必须有一个变量具有可用于保存应用程序设置的类型;在此示例中,是一个名为
applicationSettings 的 ApplicationSettings 类。您可以在代码的适当位置将要保留的属性值分配给应用程序设置类中的相应属性。如果保留的属性发生更改事件(如 BackColorChanged 事件),则可以在该事件处理程序中更新应用程序设置类中的相应属性。这样,每次用户或应用程序更改属性时,都将更新应用程序设置类的实例。
在关闭应用程序之前,调用序列化数据的方法;在此示例中,该方法名为 SaveAppSettings(),在窗体的 Closing 事件中调用。您可以在 Closing 事件处理程序中调用此方法,或者重载 Close 方法,以使用布尔值指定是否保存应用程序设置。
下面的示例更新了应用程序设置类中的属性,并将应用程序设置保存在窗体的 Closing 事件中。
' Visual Basic ' 位置更改后,将新位置保存到 ApplicationSettings ' 对象中。 Private Sub Form1_LocationChanged(sender As Object, _ e As EventArgs) Handles MyBase.LocationChanged applicationSettings.FormLocation = Me.Location End Sub ' BackColor 更改后,将新的 BackColor 保存到 ApplicationSettings ' 对象中。 Private Sub Form1_BackColorChanged(sender As Object, _ e As EventArgs) Handles MyBase.BackColorChanged applicationSettings.BackColor = Me.BackColor.ToArgb() End Sub ' 先将新的默认目录保存到 ApplicationSettings 对象中, ' 然后再序列化类设置并关闭窗体。 Private Sub Form1_Closing(sender As Object, _ e As CancelEventArgs) Handles MyBase.Closing applicationSettings.DefaultDirectory = Me.defaultDirectory applicationSettings.SaveAppSettings() End Sub // C# // 位置更改后,将新位置保存到 ApplicationSettings // 对象中。 private void Form1_LocationChanged(object sender, EventArgs e) { applictionSettings.FormLocation = this.Location; } // BackColor 更改后,将新的 BackColor 保存到 ApplicationSettings // 对象中。 private void Form1_BackColorChanged(object sender, EventArgs e) { applicationSettings.BackColor = this.BackColor.ToArgb(); } // 先将新的默认目录保存到 ApplicationSettings 对象中, // 然后再序列化类设置并关闭窗体。 private void Form1_Closing(object sender, CancelEventArgs e) { applicationSettings.DefaultDirectory = this.defaultDirectory; applicationSettings.SaveAppSettings(); }
小结
同过去一样,您可以使用适当的权限读取和写入注册表;但是,您应当限制存储在注册表中的数据量。.NET 框架使您可以轻松地序列化应用程序设置并将数据存储为 XML,而这只需要进行很少的实现和自定义工作。与 Visual Studio .NET 提供的应用程序配置模型不同,您可以读取和更新序列化的数据。
本文使用的应用程序数据和注册表数据路径符合 Windows 徽标原则。为确保您的应用程序符合 Windows 徽标原则,请参阅 Microsoft Web 站点上 Designed for Windows Logo Program 中的 Designed for Microsoft Windows XP Application Specification 部分。
在 .NET 框架中保留应用程序设置
Jeff Danner
Microsoft Corporation
2002 年 6 月
摘要:本文介绍在 Microsoft .NET 框架中,如何通过将应用程序设置保存到注册表中或将其序列化到配置文件中,在运行时保留应用程序设置。本文包含一些指向英文站点的链接。
目录
简介
保存应用程序设置的前提
使用注册表存储数据
将数据保存到注册表
从注册表检索数据
创建自定义应用程序配置类
将应用程序设置类用于应用程序
加载保存的应用程序设置
保存应用程序设置
小结
简介
保存应用程序设置是一项常见任务。过去,我们通常将设置保存到 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 ' 设置程序集属性。 <Assembly: AssemblyCompany("Microsoft")> <Assembly: AssemblyProduct("MyApplication")> <Assembly: AssemblyVersion("1.0.1")> 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.ProductVersion]。
- LocalUserAppDataPath 属性用于存储每个用户的非漫游数据;路径的形式为 [UserName]/Local Settings/Application Data/[Control.CompanyName]/[Control.ProductName]/[Control.ProductVersion]。
- CommonAppDataPath 属性用于存储计算机的非用户特定的、非漫游数据;路径的形式为 All Users/Application Data/[Control.CompanyName]/[Control.ProductName]/[Control.ProductVersion]。
注意:
数据路径中使用的
UserName 值是从
System.Environment 类的
UserName 属性检索而来的。
通常,漫游存储只能容纳较小的数据(如窗体设置),而非漫游存储可以容纳较大的数据(如大型位图的缓存)。
下面的示例包含一个存储应用程序设置的类。该类提供了用于加载(反序列化)和保存(序列化)应用程序设置的 LoadAppSettings 和 SaveAppSettings 方法。BackColor 属性值存储为整数,因此可以被序列化。该示例将序列化的数据保存到名为 MyApplication.config 的文件中。请注意,该文件不同于 Visual Studio .NET 所使用的 App.config 文件。
- 创建类并添加表明应用程序设置是否已更改的布尔型变量。确保添加对 System.Xml.Serialization 和 System.IO 命名空间的引用,并添加对可能需要用来存储数据的任何其他命名空间的引用。
' Visual Basic Imports System Imports System.Xml.Serialization Imports System.IO Imports System.Drawing Namespace Samples Public Class ApplicationSettings Private appSettingsChanged As Boolean End Class End Namespace // C# using System; using System.Xml.Serialization; using System.IO; using System.Drawing; namespace Samples { public class ApplicationSettings { private bool appSettingsChanged; } }
- 添加私有变量以存储应用程序设置,并创建公共属性访问这些变量。
' Visual Basic ' 用于存储应用程序设置的变量。 Private m_defaultDirectory As String Private m_backColor As Integer Private m_formLocation As Point ' 用于访问应用程序设置变量的属性。 Public Property DefaultDirectory() As String Get Return m_defaultDirectory End Get Set If value <> m_defaultDirectory Then m_defaultDirectory = value appSettingsChanged = True End If End Set End Property Public Property BackColor() As Integer Get Return m_backColor End Get Set If value <> m_backColor Then m_backColor = value appSettingsChanged = True End If End Set End Property Public Property FormLocation() As Point Get Return m_formLocation End Get Set If Not value.Equals(m_formLocation) Then m_formLocation = value appSettingsChanged = True End If End Set End Property // C# // 用于存储应用程序设置的变量。 private string m_defaultDirectory; private int m_backColor; private Point m_formLocation; // 用于访问应用程序设置变量的属性。 public string DefaultDirectory { get{return m_defaultDirectory;} set { if(value != m_defaultDirectory) { m_defaultDirectory = value; appSettingsChanged = true; } } } public int BackColor { get{return m_backColor;} set { if(value != m_backColor) { m_backColor = value; appSettingsChanged = true; } } } public Point FormLocation { get{return m_formLocation;} set { if(value != m_formLocation) { m_formLocation = value; appSettingsChanged = true; } } }
- 添加方法以序列化应用程序设置并将其保存到配置文件。
' Visual Basic ' 如果设置发生变化,则将 ' 类序列化到配置文件中。 Public Function SaveAppSettings() As Boolean If Me.appSettingsChanged Then Dim myWriter As StreamWriter = Nothing Dim mySerializer As XmlSerializer = Nothing Try ' 为 ApplicationSettings 类型 ' 创建 XmlSerializer。 mySerializer = New XmlSerializer( _ GetType(ApplicationSettings)) myWriter = New StreamWriter( _ Application.LocalUserAppDataPath + _ "/myApplication.config", False) ' 将 ApplicationSettings 类的这一实例 ' 序列化到配置文件中。 mySerializer.Serialize(myWriter, Me) Catch ex As Exception MessageBox.Show(ex.Message) Finally ' 如果 FileStream 是打开的,将其关闭。 If Not (myWriter Is Nothing) Then myWriter.Close() End If End Try End If Return appSettingsChanged End Function // C# // 如果设置发生变化,则将 // 类序列化到配置文件中。 public bool SaveAppSettings() { if(this.appSettingsChanged) { StreamWriter myWriter = null; XmlSerializer mySerializer = null; try { // 为 ApplicationSettings 类型 // 创建 XmlSerializer。 mySerializer = new XmlSerializer( typeof(ApplicationSettings)); myWriter = new StreamWriter(Application.LocalUserAppDataPath + @"/myApplication.config",false); // 将 ApplicationSettings 类的这一实例 // 序列化到配置文件中。 mySerializer.Serialize(myWriter, this); } catch(Exception ex) { MessageBox.Show(ex.Message); } finally { // 如果 FileStream 是打开的,将其关闭。 if(myWriter != null) { myWriter.Close(); } } } return appSettingsChanged; }
- 添加方法以从配置文件中反序列化应用程序设置。
' Visual Basic ' 从配置文件中反序列化类。 Public Function LoadAppSettings() As Boolean Dim mySerializer As XmlSerializer = Nothing Dim myFileStream As FileStream = Nothing Dim fileExists As Boolean = False Try ' 为 ApplicationSettings 类型创建 XmlSerializer。 mySerializer = New XmlSerializer(GetType(ApplicationSettings)) Dim fi As New FileInfo(Application.LocalUserAppDataPath + _ "/myApplication.config") ' 如果配置文件存在,将其打开。 If fi.Exists Then myFileStream = fi.OpenRead() ' 反序列化配置文件以创建新的 ' ApplicationSettings 实例。 Dim myAppSettings As ApplicationSettings = CType( _ mySerializer.Deserialize(myFileStream), _ ApplicationSettings) ' 为 ApplicationSettings 类的这一实例 ' 分配属性值。 Me.m_backColor = myAppSettings.BackColor Me.m_formLocation = myAppSettings.FormLocation Me.m_defaultDirectory = myAppSettings.DefaultDirectory fileExists = True End If Catch ex As Exception MessageBox.Show(ex.Message) Finally ' 如果 FileStream 是打开的,将其关闭。 If Not (myFileStream Is Nothing) Then myFileStream.Close() End If End Try ' 如果没有设置 myDirectory,则默认为 ' 用户的“我的文档”目录。 If m_defaultDirectory Is Nothing Then m_defaultDirectory = Environment.GetFolderPath( _ System.Environment.SpecialFolder.Personal) Me.appSettingsChanged = True End If Return fileExists End Function // C# // 从配置文件中反序列化类。 public bool LoadAppSettings() { XmlSerializer mySerializer = null; FileStream myFileStream = null; bool fileExists = false; try { // 为 ApplicationSettings 类型创建 XmlSerializer。 mySerializer = new XmlSerializer(typeof(ApplicationSettings)); FileInfo fi = new FileInfo(Application.LocalUserAppDataPath + @"/myApplication.config"); // 如果配置文件存在,将其打开。 if(fi.Exists) { myFileStream = fi.OpenRead(); // 反序列化配置文件以创建新的 // ApplicationSettings 实例。 ApplicationSettings myAppSettings = (ApplicationSettings)mySerializer.Deserialize( myFileStream); // 为 ApplicationSettings 类的这一实例 // 分配属性值。 this.m_backColor = myAppSettings.BackColor; this.m_formLocation = myAppSettings.FormLocation; this.m_defaultDirectory = myAppSettings.DefaultDirectory; fileExists = true; } } catch(Exception ex) { MessageBox.Show(ex.Message); } finally { // 如果 FileStream 是打开的,将其关闭。 if(myFileStream != null) { myFileStream.Close(); } } if(m_defaultDirectory == null) { // 如果没有设置 myDirectory,则默认为 // 用户的“我的文档”目录。 m_defaultDirectory = Environment.GetFolderPath( System.Environment.SpecialFolder.Personal); this.appSettingsChanged = true; } return fileExists; }
将应用程序设置类用于应用程序
您只需在应用程序中添加几行代码,便可以使用应用程序设置类对要保留的值进行序列化和反序列化。
加载保存的应用程序设置
您必须有一个变量具有可用于保存应用程序设置的类型;在此示例中,是一个名为
applicationSettings 的 ApplicationSettings 类。在代码的适当位置调用反序列化数据的方法;在此示例中,该方法名为 LoadAppSettings(),在窗体的 Load 事件中调用。您可以在任何其他初始化代码后面的构造函数中调用此方法,也可以在 Load 事件处理程序中调用。然后,将存储的值分配给应用程序的相应属性。
下面的示例在窗体的 Load 事件中加载应用程序设置,并将值分配给相应的属性。此示例假设窗体有一个名为 defaultDirectory 的变量。
' Visual Basic ' 如果 LoadAppSettings 方法成功,则将 ApplicationSettings ' 属性分配给相应的窗体属性。 Private Sub Form1_Load(sender As Object, _ e As EventArgs) Handles MyBase.Load If applicationSettings.LoadAppSettings() Then ' 从整数 (ARGB) 值中创建 Color。 Me.BackColor = Color.FromArgb(applicationSettings.BackColor) Me.Location = applicationSettings.FormLocation Me.defaultDirectory = applicationSettings.DefaultDirectory End If End Sub // C# // 如果 LoadAppSettings 方法成功,则将 ApplicationSettings // 属性分配给相应的窗体属性。 private void Form1_Load(object sender, EventArgs e) { if(this.applicationSettings.LoadAppSettings() ) { // 从整数 (ARGB) 值中创建 Color。 this.BackColor = Color.FromArgb(applicationSettings.BackColor); this.Location = applicationSettings.FormLocation; this.defaultDirectory = applicationSettings.DefaultDirectory; } }
保存应用程序设置
您必须有一个变量具有可用于保存应用程序设置的类型;在此示例中,是一个名为
applicationSettings 的 ApplicationSettings 类。您可以在代码的适当位置将要保留的属性值分配给应用程序设置类中的相应属性。如果保留的属性发生更改事件(如 BackColorChanged 事件),则可以在该事件处理程序中更新应用程序设置类中的相应属性。这样,每次用户或应用程序更改属性时,都将更新应用程序设置类的实例。
在关闭应用程序之前,调用序列化数据的方法;在此示例中,该方法名为 SaveAppSettings(),在窗体的 Closing 事件中调用。您可以在 Closing 事件处理程序中调用此方法,或者重载 Close 方法,以使用布尔值指定是否保存应用程序设置。
下面的示例更新了应用程序设置类中的属性,并将应用程序设置保存在窗体的 Closing 事件中。
' Visual Basic ' 位置更改后,将新位置保存到 ApplicationSettings ' 对象中。 Private Sub Form1_LocationChanged(sender As Object, _ e As EventArgs) Handles MyBase.LocationChanged applicationSettings.FormLocation = Me.Location End Sub ' BackColor 更改后,将新的 BackColor 保存到 ApplicationSettings ' 对象中。 Private Sub Form1_BackColorChanged(sender As Object, _ e As EventArgs) Handles MyBase.BackColorChanged applicationSettings.BackColor = Me.BackColor.ToArgb() End Sub ' 先将新的默认目录保存到 ApplicationSettings 对象中, ' 然后再序列化类设置并关闭窗体。 Private Sub Form1_Closing(sender As Object, _ e As CancelEventArgs) Handles MyBase.Closing applicationSettings.DefaultDirectory = Me.defaultDirectory applicationSettings.SaveAppSettings() End Sub // C# // 位置更改后,将新位置保存到 ApplicationSettings // 对象中。 private void Form1_LocationChanged(object sender, EventArgs e) { applictionSettings.FormLocation = this.Location; } // BackColor 更改后,将新的 BackColor 保存到 ApplicationSettings // 对象中。 private void Form1_BackColorChanged(object sender, EventArgs e) { applicationSettings.BackColor = this.BackColor.ToArgb(); } // 先将新的默认目录保存到 ApplicationSettings 对象中, // 然后再序列化类设置并关闭窗体。 private void Form1_Closing(object sender, CancelEventArgs e) { applicationSettings.DefaultDirectory = this.defaultDirectory; applicationSettings.SaveAppSettings(); }
小结
同过去一样,您可以使用适当的权限读取和写入注册表;但是,您应当限制存储在注册表中的数据量。.NET 框架使您可以轻松地序列化应用程序设置并将数据存储为 XML,而这只需要进行很少的实现和自定义工作。与 Visual Studio .NET 提供的应用程序配置模型不同,您可以读取和更新序列化的数据。
本文使用的应用程序数据和注册表数据路径符合 Windows 徽标原则。为确保您的应用程序符合 Windows 徽标原则,请参阅 Microsoft Web 站点上 Designed for Windows Logo Program 中的 Designed for Microsoft Windows XP Application Specification 部分。