前言
VS
给我们提供非常方便的程序配置文件管理功能,可视化操作,还是非常棒的,但一些高级操作仍需要手动写代码,之前我想要将程序的user.config
存储路径改为其运行目录,发现默认不可以,所以打算造一下轮子,自己用代码实现,但是又发现轮子别人有,不多说,复制粘贴就用起来,顺便做个记录,真香。
SettingsProvider
来自参考资料2
中的代码,这里感谢kenvix
,需要的朋友自行魔改。
- GetAppSettingsPath() 的返回值为 设置存储目录
- GetAppSettingsFilename() 的返回值为 设置文件名
- SkipRoamingCheck 是否跳过漫游属性检测,无特殊需求建议为 true
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;
}
}
}
参考资料
https://classpattern.com/customsettingsprovider-csharp
https://kenvix.com/post/csharp-custom-appsettings-path/
https://msdn.microsoft.com/zh-cn/library/a65txexh.aspx