C# 实现自定义"应用程序设置"的配置文件(user.config)存储路径

关于“应用程序设置”: 前往MSDN查看

默认提供的 SettingsProvider 不允许我们修改应用程序设置的配置文件的路径,这就导致了以下问题:

  1. 设置保存在了 %appdata% 目录下,使应用程序不够绿色化
  2. 当用户把程序拷贝到其他电脑上时,设置将丢失
  3. 当用户升级程序时,设置将丢失(自带的 Upgrade() 过于复杂)

要解决上述问题,就需要由我们自己来定义在哪里存储应用程序设置
MSDN给出的方法是:自己实现一个 SettingsProvider

动手

“应用程序设置” 在 C# 2.0 就已经被引入,但网上关于 SettingsProvider 的轮子并不多,我自己找到了一个比较完整的,用 vb.net 写的轮子,并人力翻译成了 c#,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
using System;
using System.Collections;
using System.Configuration;
using System.Collections.Specialized;
using System.Xml;
using System.Windows.Forms;
using System.IO;

namespace Kenvix
{
public class AppConfigProvider : SettingsProvider
{
const string SettingsRootNode = "Settings"; // XML Root Node
const bool SkipRoamingCheck = false; //if true, all settings will be forcely marked as Roaming

/// <summary>
/// Used to determine where to store the settings
/// </summary>
/// <returns></returns>
public virtual string GetAppSettingsPath()
{
return (new FileInfo(Application.ExecutablePath)).DirectoryName; //Use application path
}

/// <summary>
/// Used to determine the filename to store the settings
/// </summary>
/// <returns></returns>
public virtual string GetAppSettingsFilename()
{
return ApplicationName + ".config";
}


public override void Initialize(string name, NameValueCollection col)
{
base.Initialize(ApplicationName, col);
}

public override string ApplicationName
{
get
{
return Application.ProductName;
}
set { }
}

/// <summary>
/// Iterate through the settings to be stored
/// Only dirty settings are included in propvals, and only ones relevant to this provider
/// </summary>
/// <param name="context"></param>
/// <param name="propvals"></param>
public override void SetPropertyValues(SettingsContext context, SettingsPropertyValueCollection propvals)
{
foreach (SettingsPropertyValue propval in propvals)
SetValue(propval);

SettingsXML.Save(Path.Combine(GetAppSettingsPath(), GetAppSettingsFilename()));
}

public override SettingsPropertyValueCollection GetPropertyValues(SettingsContext context, SettingsPropertyCollection props)
{
// Create new collection of values
SettingsPropertyValueCollection values = new SettingsPropertyValueCollection();

// Iterate through the settings to be retrieved
foreach (SettingsProperty setting in props)
{
SettingsPropertyValue value = new SettingsPropertyValue(setting);
value.IsDirty = false;
value.SerializedValue = GetValue(setting);
values.Add(value);
}
return values;
}

private XmlDocument m_SettingsXML = null;

private XmlDocument SettingsXML
{
get
{
// If we dont hold an xml document, try opening one.
// If it doesnt exist then create a new one ready.
if (m_SettingsXML == null)
{
m_SettingsXML = new XmlDocument();

try
{
m_SettingsXML.Load(Path.Combine(GetAppSettingsPath(), GetAppSettingsFilename()));
}
catch (Exception)
{
// Create new document
XmlDeclaration dec = m_SettingsXML.CreateXmlDeclaration("1.0", "utf-8", string.Empty);
m_SettingsXML.AppendChild(dec);

XmlNode nodeRoot;

nodeRoot = m_SettingsXML.CreateNode(XmlNodeType.Element, SettingsRootNode, "");
m_SettingsXML.AppendChild(nodeRoot);
}
}

return m_SettingsXML;
}
}

private string GetValue(SettingsProperty setting)
{
string ret = "";

try
{
if (IsRoaming(setting))
ret = SettingsXML.SelectSingleNode(SettingsRootNode + "/" + setting.Name).InnerText;
else
ret = SettingsXML.SelectSingleNode(SettingsRootNode + "/" + Environment.MachineName + "/" + setting.Name).InnerText;
}
catch (Exception)
{
if (setting.DefaultValue != null)
ret = setting.DefaultValue.ToString();
else
ret = "";
}

return ret;
}

private void SetValue(SettingsPropertyValue propVal)
{
XmlElement MachineNode;
XmlElement SettingNode;

// Determine if the setting is roaming.
// If roaming then the value is stored as an element under the root
// Otherwise it is stored under a machine name node
try
{
if (IsRoaming(propVal.Property))
SettingNode = (XmlElement)SettingsXML.SelectSingleNode(SettingsRootNode + "/" + propVal.Name);
else
SettingNode = (XmlElement)SettingsXML.SelectSingleNode(SettingsRootNode + "/" + Environment.MachineName + "/" + propVal.Name);
}
catch (Exception)
{
SettingNode = null;
}

// Check to see if the node exists, if so then set its new value
if (SettingNode != null)
SettingNode.InnerText = propVal.SerializedValue.ToString();
else if (IsRoaming(propVal.Property))
{
// Store the value as an element of the Settings Root Node
SettingNode = SettingsXML.CreateElement(propVal.Name);
SettingNode.InnerText = propVal.SerializedValue.ToString();
SettingsXML.SelectSingleNode(SettingsRootNode).AppendChild(SettingNode);
}
else
{
// Its machine specific, store as an element of the machine name node,
// creating a new machine name node if one doesnt exist.
try
{
MachineNode = (XmlElement)SettingsXML.SelectSingleNode(SettingsRootNode + "/" + Environment.MachineName);
}
catch (Exception)
{
MachineNode = SettingsXML.CreateElement(Environment.MachineName);
SettingsXML.SelectSingleNode(SettingsRootNode).AppendChild(MachineNode);
}

if (MachineNode == null)
{
MachineNode = SettingsXML.CreateElement(Environment.MachineName);
SettingsXML.SelectSingleNode(SettingsRootNode).AppendChild(MachineNode);
}

SettingNode = SettingsXML.CreateElement(propVal.Name);
SettingNode.InnerText = propVal.SerializedValue.ToString();
MachineNode.AppendChild(SettingNode);
}
}

/// <summary>
/// Determine if the setting is marked as Roaming
/// </summary>
/// <param name="prop"></param>
/// <returns></returns>
private bool IsRoaming(SettingsProperty prop)
{
if (SkipRoamingCheck) return true;
foreach (DictionaryEntry d in prop.Attributes)
{
Attribute a = (Attribute)d.Value;
if (a is SettingsManageabilityAttribute)
return true;
}
return false;
}
}

}

GetAppSettingsPath() 的返回值为 设置存储目录
GetAppSettingsFilename() 的返回值为 设置文件名
SkipRoamingCheck 是否跳过漫游属性检测,无特殊需求建议为 true

使用

使用上述代码的方法非常简单,只需:

  1. 把上述代码加入你的项目
  2. 如下图,双击打开 设置设计器
  3. 如下图,对于 每一个设置项,修改属性为下图:

转载请遵守 CC BY-NC-SA 4.0 协议并注明来自:C# 实现自定义"应用程序设置"的配置文件(user.config)存储路径

Loading...

电子邮件地址不会被公开。 必填项已用 * 标注

Powered by Kenvix Comment Server v1.0