在软件开发中,应用程序范围的设置通常用于存储跨会话的用户偏好或配置信息。这些设置可以是只读的,也可以是可写的。本文将介绍一种简单而通用的方法来创建和使用自定义的可写应用程序范围设置。
为了实现自定义设置,希望它们能够像现有的项目设置一样被使用。下面是一个设置属性的示例,使用自定义设置类MySettings
和该类上的属性OptionA
:
CustomProperties<MySettings>.Settings.Default.OptionA = true;
类图CustomProperties<T>
,其中T
是设置类:
类CustomProperties
通过Settings
属性创建为单例。属性Default
引用类型T
(设置类)的实例。
public class CustomProperties<T> where T : class
{
private static CustomProperties<T> settings;
public T Default {
get;
private set;
}
public static CustomProperties<T> Settings
{
get
{
return settings ?? (settings = new CustomProperties<T>());
}
}
}
为了进一步说明应用程序范围设置的使用,创建了一个小型测试应用程序。该应用程序使用一个示例设置类MySettings
,包含两个布尔选项和一个字符串列表,用于选择选项。
以下是在测试应用程序中加载设置的代码:
private void InitializeSettings()
{
collection = new ObservableCollection<string>(CustomProperties<MySettings>.Settings.Default.SelectedOptions);
listBoxSelectedOptions.ItemsSource = collection;
checkBoxOptionA.IsChecked = CustomProperties<MySettings>.Settings.Default.OptionA;
checkBoxOptionB.IsChecked = CustomProperties<MySettings>.Settings.Default.OptionB;
SettingsFile.NavigateUri = new Uri(CustomProperties<MySettings>.Settings.SettingsFile);
}
保存设置的代码如下:
private void buttonSave_Click(object sender, RoutedEventArgs e)
{
CustomProperties<MySettings>.Settings.Default.OptionA = checkBoxOptionA.IsChecked == true;
CustomProperties<MySettings>.Settings.Default.OptionB = checkBoxOptionB.IsChecked == true;
CustomProperties<MySettings>.Settings.Default.SelectedOptions = new List<string>(collection);
CustomProperties<MySettings>.Settings.Save();
}
设置通过序列化存储在以下路径:
C:\[CommonAppData]\[ProductName]\[name of T].xml
如果产品名称为空或找不到,将使用条目程序集或执行程序集的名称。对于测试应用程序,路径解析为:
C:\ProgramData\ApplicationScopeSettingsTest\MySettings.xml
设置的加载和保存使用XmlSerializer
进行。
以下是加载指定XML文件的方法:
private T Load()
{
if (!settingsFile.Exists)
return default(T);
var serializer = new XmlSerializer(typeof(T));
using (XmlReader reader = new XmlTextReader(File.OpenRead(settingsFile.FullName)))
{
return (T)serializer.Deserialize(reader);
}
}
以下是保存设置的方法:
public void Save()
{
var serializer = new XmlSerializer(typeof(T));
using (XmlWriter writer = new XmlTextWriter(File.Create(settingsFile.FullName), Encoding.UTF8))
{
serializer.Serialize(writer, Default);
}
}
当CustomProperties
被加载且没有找到以前的设置时,它将创建一个设置(类型T
)的实例,使用其默认值。创建具有默认值的设置实例:
Default = (T)Activator.CreateInstance(typeof(T));
如果在设置类的构造函数中为列表或集合分配了任何值,那么在加载(反序列化)设置时会导致额外的项目被加载。为了解决这个问题,在MySettings
类上创建了另一个构造函数,它接受一个布尔值,所以有两种方式来创建设置。如下所示:
const bool initializeObject = true;
Default = (T)Activator.CreateInstance(typeof(T), new object[] { initializeObject });
修改后的设置类MySettings
:
public MySettings() : this(false)
{
}
public MySettings(bool initializeValues)
{
OptionA = false;
OptionB = true;
SelectedOptions = new List<string>();
if (!initializeValues)
return;
SelectedOptions.AddRange(new List<string> { "Red", "Blue" });
}
这将确保从文件反序列化设置和使用默认值创建设置类实例都能正常工作。如果不为列表或集合分配任何值,可以安全地删除重载并修改CreateInstance<T>
方法以省略值。
CustomProperties<T>
也可以用于创建自定义用户范围设置。这可以通过更改设置文件的位置来实现,引用Environment.SpecialFolder.ApplicationData
。ApplicationData和CommonAppData路径可以作为受限用户写入。