我想要实现的非常简单:我有一个Windows窗体(.NET 3.5)应用程序,它使用一个路径来读取信息。用户可以使用我提供的选项表单修改此路径。
现在,我想将路径值保存到文件中供以后使用。这将是保存到此文件的众多设置之一。该文件将直接位于应用程序文件夹中。
我理解有三种选择:
我读到.NET配置文件没有预见到将值保存回来。 至于注册表,我希望尽可能远离它。
这是否意味着我应该使用自定义XML文件来保存配置设置? 如果是这样,我希望看到代码示例(C#)。
我已经看过关于这个问题的其他讨论,但我仍然不清楚。
答案 0 :(得分:564)
如果您使用Visual Studio,那么获得可持久设置非常容易。在Solution Explorer中右键单击项目,选择Properties。选择“设置”选项卡,如果设置不存在,请单击超链接。使用“设置”选项卡创建应用程序设置。 Visual Studio会创建包含从ApplicationSettingsBase继承的单例类Settings.settings
的文件Settings.Designer.settings
和Settings
。您可以从代码中访问此类以读取/写入应用程序设置:
Properties.Settings.Default["SomeProperty"] = "Some Value";
Properties.Settings.Default.Save(); // Saves settings in application configuration file
此技术适用于控制台,Windows窗体和其他项目类型。
请注意,您需要设置设置的范围属性。如果选择“应用程序范围”,则选择“Settings.Default”。你的财产>将是只读的。
答案 1 :(得分:88)
如果您打算保存到与可执行文件相同的目录中的文件,这是一个使用JSON格式的好解决方案:
using System;
using System.IO;
using System.Web.Script.Serialization;
namespace MiscConsole
{
class Program
{
static void Main(string[] args)
{
MySettings settings = MySettings.Load();
Console.WriteLine("Current value of 'myInteger': " + settings.myInteger);
Console.WriteLine("Incrementing 'myInteger'...");
settings.myInteger++;
Console.WriteLine("Saving settings...");
settings.Save();
Console.WriteLine("Done.");
Console.ReadKey();
}
class MySettings : AppSettings<MySettings>
{
public string myString = "Hello World";
public int myInteger = 1;
}
}
public class AppSettings<T> where T : new()
{
private const string DEFAULT_FILENAME = "settings.json";
public void Save(string fileName = DEFAULT_FILENAME)
{
File.WriteAllText(fileName, (new JavaScriptSerializer()).Serialize(this));
}
public static void Save(T pSettings, string fileName = DEFAULT_FILENAME)
{
File.WriteAllText(fileName, (new JavaScriptSerializer()).Serialize(pSettings));
}
public static T Load(string fileName = DEFAULT_FILENAME)
{
T t = new T();
if(File.Exists(fileName))
t = (new JavaScriptSerializer()).Deserialize<T>(File.ReadAllText(fileName));
return t;
}
}
}
答案 2 :(得分:66)
注册表是禁止的。您不确定使用您的应用程序的用户是否有足够的权限写入注册表。
您可以使用app.config
文件来保存应用程序级设置(对于使用您的应用程序的每个用户都是相同的)。
我会将用户特定的设置存储在XML文件中,该文件将保存在Isolated Storage或SpecialFolder.ApplicationData目录中。
接下来,从.NET 2.0开始,可以将值存储回app.config
文件。
答案 3 :(得分:20)
ApplicationSettings
类不支持将设置保存到app.config文件。这非常依赖于设计,使用正确安全的用户帐户(想想Vista UAC)运行的应用程序没有对程序安装文件夹的写入权限。
您可以使用ConfigurationManager
课程与系统对战。但是,简单的解决方法是进入“设置”设计器并将设置的范围更改为“用户”。如果这会导致困难(例如,设置与每个用户相关),则应将“选项”功能放在单独的程序中,以便可以请求权限提升提示。或放弃使用设置。
答案 4 :(得分:15)
我想分享一个我为此而建的库。它是一个很小的库,但对.settings文件有很大改进(恕我直言)。
该库名为Jot (GitHub),这是我写的一篇旧版The Code Project article。
以下是如何使用它来跟踪窗口的大小和位置:
public MainWindow()
{
InitializeComponent();
_stateTracker.Configure(this)
.IdentifyAs("MyMainWindow")
.AddProperties(nameof(Height), nameof(Width), nameof(Left), nameof(Top), nameof(WindowState))
.RegisterPersistTrigger(nameof(Closed))
.Apply();
}
与.settings文件相比的好处:代码相当少,并且它更容易出错,因为您只需要提及每个属性一次。
使用设置文件,您需要提及每个属性五次次:一次是在显式创建属性时,另外四次是在代码中来回复制值。
存储,序列化等是完全可配置的。当目标对象由IOC容器创建时,您可以[挂钩] []以便它自动将跟踪应用于它所解析的所有对象,这样您需要做的就是使属性持久化是一个[Trackable]属性在它上面。
它具有高度可配置性,您可以配置: - 在全局或每个跟踪对象中持久保存和应用数据时 - 它是如何序列化的 - 存储的位置(例如文件,数据库,在线,隔离存储,注册表) - 可以取消应用/保留属性数据的规则
相信我,图书馆是一流的!
答案 5 :(得分:14)
registry / configurationSettings / XML参数似乎仍然非常活跃。我已经全部使用了它们,因为技术已经取得了进展,但我最喜欢的是基于Threed's system和Isolated Storage。
以下示例允许将名为properties的对象存储到隔离存储中的文件中。如:
AppSettings.Save(myobject, "Prop1,Prop2", "myFile.jsn");
可以使用以下方法恢复属性:
AppSettings.Load(myobject, "myFile.jsn");
这只是一个样本,并不是最佳实践的暗示。
internal static class AppSettings
{
internal static void Save(object src, string targ, string fileName)
{
Dictionary<string, object> items = new Dictionary<string, object>();
Type type = src.GetType();
string[] paramList = targ.Split(new char[] { ',' });
foreach (string paramName in paramList)
items.Add(paramName, type.GetProperty(paramName.Trim()).GetValue(src, null));
try
{
// GetUserStoreForApplication doesn't work - can't identify.
// application unless published by ClickOnce or Silverlight
IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForAssembly();
using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(fileName, FileMode.Create, storage))
using (StreamWriter writer = new StreamWriter(stream))
{
writer.Write((new JavaScriptSerializer()).Serialize(items));
}
}
catch (Exception) { } // If fails - just don't use preferences
}
internal static void Load(object tar, string fileName)
{
Dictionary<string, object> items = new Dictionary<string, object>();
Type type = tar.GetType();
try
{
// GetUserStoreForApplication doesn't work - can't identify
// application unless published by ClickOnce or Silverlight
IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForAssembly();
using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(fileName, FileMode.Open, storage))
using (StreamReader reader = new StreamReader(stream))
{
items = (new JavaScriptSerializer()).Deserialize<Dictionary<string, object>>(reader.ReadToEnd());
}
}
catch (Exception) { return; } // If fails - just don't use preferences.
foreach (KeyValuePair<string, object> obj in items)
{
try
{
tar.GetType().GetProperty(obj.Key).SetValue(tar, obj.Value, null);
}
catch (Exception) { }
}
}
}
答案 6 :(得分:11)
一种简单的方法是使用配置数据对象,将其保存为XML文件,并在本地文件夹中包含应用程序的名称,并在启动时将其读回。
以下是存储表单位置和大小的示例。
配置数据对象是强类型的并且易于使用:
[Serializable()]
public class CConfigDO
{
private System.Drawing.Point m_oStartPos;
private System.Drawing.Size m_oStartSize;
public System.Drawing.Point StartPos
{
get { return m_oStartPos; }
set { m_oStartPos = value; }
}
public System.Drawing.Size StartSize
{
get { return m_oStartSize; }
set { m_oStartSize = value; }
}
}
用于保存和加载的经理类:
public class CConfigMng
{
private string m_sConfigFileName = System.IO.Path.GetFileNameWithoutExtension(System.Windows.Forms.Application.ExecutablePath) + ".xml";
private CConfigDO m_oConfig = new CConfigDO();
public CConfigDO Config
{
get { return m_oConfig; }
set { m_oConfig = value; }
}
// Load configuration file
public void LoadConfig()
{
if (System.IO.File.Exists(m_sConfigFileName))
{
System.IO.StreamReader srReader = System.IO.File.OpenText(m_sConfigFileName);
Type tType = m_oConfig.GetType();
System.Xml.Serialization.XmlSerializer xsSerializer = new System.Xml.Serialization.XmlSerializer(tType);
object oData = xsSerializer.Deserialize(srReader);
m_oConfig = (CConfigDO)oData;
srReader.Close();
}
}
// Save configuration file
public void SaveConfig()
{
System.IO.StreamWriter swWriter = System.IO.File.CreateText(m_sConfigFileName);
Type tType = m_oConfig.GetType();
if (tType.IsSerializable)
{
System.Xml.Serialization.XmlSerializer xsSerializer = new System.Xml.Serialization.XmlSerializer(tType);
xsSerializer.Serialize(swWriter, m_oConfig);
swWriter.Close();
}
}
}
现在您可以创建一个实例并在表单的加载和关闭事件中使用:
private CConfigMng oConfigMng = new CConfigMng();
private void Form1_Load(object sender, EventArgs e)
{
// Load configuration
oConfigMng.LoadConfig();
if (oConfigMng.Config.StartPos.X != 0 || oConfigMng.Config.StartPos.Y != 0)
{
Location = oConfigMng.Config.StartPos;
Size = oConfigMng.Config.StartSize;
}
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
// Save configuration
oConfigMng.Config.StartPos = Location;
oConfigMng.Config.StartSize = Size;
oConfigMng.SaveConfig();
}
生成的XML文件也是可读的:
<?xml version="1.0" encoding="utf-8"?>
<CConfigDO xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<StartPos>
<X>70</X>
<Y>278</Y>
</StartPos>
<StartSize>
<Width>253</Width>
<Height>229</Height>
</StartSize>
</CConfigDO>
答案 7 :(得分:7)
我不喜欢使用web.config
或app.config
的建议解决方案。尝试阅读自己的XML。请查看 XML Settings Files – No more web.config 。
答案 8 :(得分:4)
其他选项,我们可以使用更友好的文件格式:JSON或YAML文件,而不是使用自定义XML文件。
您可以将设置文件存储在多个特殊文件夹(适用于所有用户和每个用户)中,如Environment.SpecialFolder Enumeration所示,以及多个文件(默认只读,每个角色,每个用户等)
如果您选择使用多个设置,则可以合并这些设置:例如,合并默认设置+ BasicUser + AdminUser的设置。您可以使用自己的规则:最后一个规则会覆盖值等。
答案 9 :(得分:3)
据我所知,.NET确实支持使用内置应用程序设置工具的持久设置:
Windows窗体的“应用程序设置”功能使您可以轻松地在客户端计算机上创建,存储和维护自定义应用程序和用户首选项。使用Windows窗体应用程序设置,您不仅可以存储应用程序数据(如数据库连接字符串),还可以存储用户特定的数据,例如用户应用程序首选项。使用Visual Studio或自定义托管代码,您可以创建新设置,从中读取并将其写入磁盘,将它们绑定到表单上的属性,并在加载和保存之前验证设置数据。 - http://msdn.microsoft.com/en-us/library/k4s6c3a0.aspx
答案 10 :(得分:3)
&#34;这是否意味着我应该使用自定义XML文件来保存配置设置?&#34;不,不一定。我们使用SharpConfig进行此类操作。
例如,如果配置文件是那样的
[General]
# a comment
SomeString = Hello World!
SomeInteger = 10 # an inline comment
我们可以检索这样的值
var config = Configuration.LoadFromFile("sample.cfg");
var section = config["General"];
string someString = section["SomeString"].StringValue;
int someInteger = section["SomeInteger"].IntValue;
它与.Net 2.0及更高版本兼容。我们可以动态创建配置文件,我们可以稍后保存。 资料来源:http://sharpconfig.net/ Github:https://github.com/cemdervis/SharpConfig
我希望它有所帮助。
答案 11 :(得分:2)
有时您想要摆脱传统web.config或app.config文件中保留的设置。您希望对设置条目的部署和分离的数据设计进行更细粒度的控制。或者要求是在运行时启用添加新条目。
我可以想象两个不错的选择:
强类型版本的优点是强类型设置名称和值。不存在混用名称或数据类型的风险。缺点是必须编码更多设置,不能在运行时添加。
使用面向对象的版本,优点是可以在运行时添加新设置。但是你没有强类型的名字和值。必须小心使用字符串标识符。获取值时必须知道先前保存的数据类型。
您可以找到两个功能齐全的实现HERE的代码。
答案 12 :(得分:2)
是的,可以保存-但它很大程度上取决于您选择的配置方式。让我描述一下技术差异,以便您了解所拥有的选项:
首先,您需要区分是要在*.exe.config
(在Visual Studio中又称为App.config
)中使用 applicationSettings 还是 AppSettings 文件-有基本区别 being described here。
两者都提供了不同的更改保存方式:
config.Save(ConfigurationSaveMode.Modified);
,其中config定义为config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
)。Properties.Settings.Default.Save();
),则将按用户写入,并存储在特殊位置(例如C:\Documents and Settings\USERID\Local Settings\Application Data\FIRMNAME\WindowsFormsTestApplicati_Url_tdq2oylz33rzq00sxhvxucu5edw2oghw\1.0.0.0
)。正如他的回答Hans Passant mentioned一样,这是因为用户通常对程序文件具有受限的权限,并且在不调用UAC提示符的情况下无法对其进行写入。一个缺点是,如果将来要添加配置密钥,则需要将其与每个用户配置文件同步。 注意:如问题中所述,有一个第3个选项::如果您将配置文件视为 XML文档,使用System.Xml.Linq.XDocument
类来加载,修改和保存它。不需要使用自定义XML文件,您可以读取现有的配置文件。对于查询元素,您甚至可以使用Linq查询。我给出了一个示例 here ,在答案中查看了功能 GetApplicationSetting
。
如果您需要加密来保护您的值,请查看 this 答案。
答案 13 :(得分:1)
Date