使应用程序设置可移植
如何为 .NET 应用程序创建自定义设置提供程序
引言
本文介绍了如何将 .NET 应用程序的设置存储在应用程序文件夹中(或任何其他位置),以便与应用程序一起便携。这通过创建自定义设置提供程序来实现,该提供程序负责加载和存储设置。
此实现的更新版本,进行了一些小修改,托管在 GitHub 上:https://github.com/bluegrams/SettingsProviders。还有一个尝试将设置存储为 JSON 格式的设置提供程序,也可以在那里找到。
背景
.NET 提供了一个集成的应用程序和用户设置存储机制,使开发人员能够轻松创建和使用这些设置。简要概述:Windows Forms(或 WPF)的设置通常分为两类:每个用户账户存储的可读写用户范围设置,以及应用程序范围设置,后者在运行时通常是只读的。这两种类型都通过一个派生自 ApplicationSettingsBase
的设置类进行访问,该类提供了设置属性以及加载和保存的基本方法。
然而,实际数据由一个派生自 SettingsProvider
的类提供,该类负责加载和存储数据。默认设置提供程序以类似 XML 的格式将用户范围设置存储在用户 AppData 文件夹中的 user.config 文件中。这对于典型应用程序来说已经足够了,但在某些情况下(例如,不希望修改 AppData 文件夹的便携式应用程序),首选备用的存储位置。由于无法更改默认设置提供程序的存储位置,因此我们必须实现自己的设置提供程序。这并不复杂,只需要实现几个方法。尽管如此,还是有一些棘手的问题需要考虑。
Using the Code
标准方法
通过 Visual Studio 可以轻松地将便携式设置提供程序应用于你的应用程序设置。为此,请转到设置设计器,选择一个设置,然后打开其属性页面。它包含一个默认为空的 Provider
字段,将其设置为提供程序的名称。请注意,你必须指定类的完整名称,包括命名空间,在本例中是 Bluegrams.Application.PortableSettingsProvider
。
还值得注意的是,通过这种方式,必须为每个设置属性单独设置设置提供程序。这提供了灵活性,但对于大型设置文件来说,可能不是最简单的方法。
快速方法
因此,这个便携式设置提供程序的实现提供了一种更简单的方法。要使设置类中的所有设置便携,只需像这样使用其 ApplyProvider()
方法即可
// make the default settings class portable
PortableSettingsProvider.ApplyProvider(Properties.Settings.Default);
配置文件
应用后,便携式设置提供程序会将用户范围的设置存储在应用程序文件夹中的一个名为 portable.config 的文件中。如果此文件不存在,则使用默认值,并创建一个新文件。数据以类似 XML 风格的格式序列化,类似于默认的设置文件。
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<userSettings>
<Roaming>
<Bluegrams.Application.WPF.Properties.Settings>
<Culture></Culture>
</Bluegrams.Application.WPF.Properties.Settings>
<TestWpfApp.Properties.Settings>
<RoamedSetting>Default text</RoamedSetting>
</TestWpfApp.Properties.Settings>
</Roaming>
<PC_MachineName>
<Bluegrams.Application.WPF.Properties.Settings>
<Width>640</Width>
<Height>480</Height>
<Left>100</Left>
<Top>100</Top>
</Bluegrams.Application.WPF.Properties.Settings>
<TestWpfApp.Properties.Settings>
<LocalSetting>Default text</LocalSetting>
</TestWpfApp.Properties.Settings>
</PC_MachineName>
</userSettings>
</configuration>
有几点值得注意。首先,文件分为一个 <Roaming>
部分和一个与当前 PC 同名的部分。漫游部分中的属性是可移植到另一台计算机的属性,而所有其他设置则特定于一台计算机(例如窗口位置或大小等设置应在此处找到)。要将设置放入漫游部分,只需为此设置设置 Roaming
属性为 true
(参见上图)。
然后,settings
属性会进一步划分为它们所属的设置类。这使得来自不同位置的不同类可以共享同一个 settings 文件。
关注点
自定义设置提供程序只需要实现三个方法,其中 GetPropertyValues()
和 SetPropertyValues()
是两个重要的。这些方法接收一组设置属性,并执行 XML 文件的加载或保存。由于提供程序应仅处理用户范围的设置,并且必须区分漫游和非漫游设置,因此 IsRoaming()
和 IsUserScoped()
方法会遍历属性的属性来检查这一点。IsRoaming()
方法搜索 SettingsManageabilityAttribute
,而 IsUserScoped()
方法指示是否存在 UserScopedSettingAttribute
。
作为第三种方法,必须从基类重写 Initialize()
。在此,指定 name
参数的值很重要,因为此参数不能留空。
接下来,我们确保 Reload()
方法按预期工作。为此,设置提供程序本身不会缓存任何加载的 XML 内容,而是在每次调用 GetPropertyValues()
方法时从文件加载设置。这听起来效率极低,但设置类本身会缓存属性,因此只有在确实需要重新加载设置时(例如,调用了 Reload()
方法),设置提供程序才会介入。
最后一点值得关注的是每个设置类中可用的 Reset()
和 Upgrade()
方法。为了支持这些方法,设置提供程序必须实现一个名为 IApplicationSettingsProvider
的 interface
。在此实现中,Reset()
方法会简单地删除设置文件,以将所有设置重置为其默认值。
历史
- 2018-11-17:修复了实现中的几个 bug
- 2018-04-08:初始版本