如何在 Windows 窗体应用程序中保存应用程序设置?

发布于 2024-07-12 04:20:52 字数 442 浏览 22 评论 0 原文

我想要实现的目标非常简单:我有一个 Windows 窗体(.NET 3.5)应用程序,它使用路径来读取信息。 用户可以使用我提供的选项表单来修改此路径。

现在,我想将路径值保存到文件中以供以后使用。 这将是保存到该文件的众多设置之一。 该文件将直接位于应用程序文件夹中。

据我所知,可以使用三个选项:

  • ConfigurationSettings 文件 (appname.exe.config)
  • 注册表
  • 自定义 XML 文件

我读到,.NET 配置文件预计不会将值保存回其中。 至于注册表,我想尽可能远离它。

这是否意味着我应该使用自定义 XML 文件来保存配置设置?

如果是这样,我想看看它的代码示例(C#)。

我看过其他关于这个主题的讨论,但我仍然不清楚。

What I want to achieve is very simple: I have a Windows Forms (.NET 3.5) application that uses a path for reading information. This path can be modified by the user, by using the options form I provide.

Now, I want to save the path value to a file for later use. This would be one of the many settings saved to this file. This file would sit directly in the application folder.

I understand three options are available:

  • ConfigurationSettings file (appname.exe.config)
  • Registry
  • Custom XML file

I read that the .NET configuration file is not foreseen for saving values back to it. As for the registry, I would like to get as far away from it as possible.

Does this mean that I should use a custom XML file to save configuration settings?

If so, I would like to see code example of that (C#).

I have seen other discussions on this subject, but it is still not clear to me.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(14

紫瑟鸿黎 2024-07-19 04:20:52

如果您使用 Visual Studio,则很容易获得持久设置。 右键单击“解决方案资源管理器”中的项目并选择“属性”。 选择“设置”选项卡,如果设置不存在,则单击超链接。

使用“设置”选项卡创建应用程序设置。 Visual Studio 创建文件 Settings.settingsSettings.Designer.settings,其中包含继承自 ApplicationSettingsBase。 您可以从代码中访问此类以读取/写入应用程序设置:

Properties.Settings.Default["SomeProperty"] = "Some Value";
Properties.Settings.Default.Save(); // Saves settings in application configuration file

此技术适用于控制台、Windows 窗体和其他项目类型。

请注意,您需要设置设置的范围属性。 如果您选择“应用程序范围”,则选择“Settings.Default”。<您的属性> 将是只读的。

参考:如何:使用 C# 在运行时编写用户设置 - Microsoft Docs

If you work with Visual Studio then it is pretty easy to get persistable settings. Right click on the project in Solution Explorer and choose Properties. Select the Settings tab and click on the hyperlink if settings doesn't exist.

Use the Settings tab to create application settings. Visual Studio creates the files Settings.settings and Settings.Designer.settings that contain the singleton class Settings inherited from ApplicationSettingsBase. You can access this class from your code to read/write application settings:

Properties.Settings.Default["SomeProperty"] = "Some Value";
Properties.Settings.Default.Save(); // Saves settings in application configuration file

This technique is applicable both for console, Windows Forms, and other project types.

Note that you need to set the scope property of your settings. If you select Application scope then Settings.Default.<your property> will be read-only.

Reference: How To: Write User Settings at Run Time with C# - Microsoft Docs

生来就爱笑 2024-07-19 04:20:52

如果您计划将文件保存到与可执行文件相同的目录中,这里有一个很好的解决方案,它使用 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;
        }
    }
}

If you are planning on saving to a file within the same directory as your executable, here's a nice solution that uses the JSON format:

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;
        }
    }
}
执着的年纪 2024-07-19 04:20:52

注册表是不行的。 您不确定使用您的应用程序的用户是否有足够的权限写入注册表。

您可以使用 app.config 文件保存应用程序级别的设置(对于使用您的应用程序的每个用户来说都是相同的)。

我会将用户特定的设置存储在 XML 文件中,该文件将保存在 独立存储SpecialFolder.ApplicationData< /a> 目录。

除此之外,从 .NET 2.0 开始,可以将值存储回 app.config 文件。

The registry is a no-go. You're not sure whether the user which uses your application, has sufficient rights to write to the registry.

You can use the app.config file to save application-level settings (that are the same for each user who uses your application).

I would store user-specific settings in an XML file, which would be saved in Isolated Storage or in the SpecialFolder.ApplicationData directory.

Next to that, as from .NET 2.0, it is possible to store values back to the app.config file.

囚我心虐我身 2024-07-19 04:20:52

ApplicationSettings 类不支持将设置保存到 app.config 文件中。 这很大程度上是设计使然。 使用正确保护的用户帐户(例如 Vista UAC)运行的应用程序没有对该程序的安装文件夹的写入权限。

您可以使用 ConfigurationManager 类来对抗系统。 但简单的解决方法是进入“设置”设计器并将设置的范围更改为“用户”。 如果这会导致困难(例如,该设置与每个用户相关),您应该将“选项”功能放在单独的程序中,以便可以请求权限提升提示。 或者放弃使用某个设置。

The ApplicationSettings class doesn't support saving settings to the app.config file. That's very much by design; applications that run with a properly secured user account (think Vista UAC) do not have write access to the program's installation folder.

You can fight the system with the ConfigurationManager class. But the trivial workaround is to go into the Settings designer and change the setting's scope to User. If that causes hardships (say, the setting is relevant to every user), you should put your Options feature in a separate program so you can ask for the privilege elevation prompt. Or forego using a setting.

谈场末日恋爱 2024-07-19 04:20:52

我想分享我为此构建的库。 这是一个很小的库,但相对于 .settings 文件来说是一个很大的改进(恕我直言)。

该库名为 Jot (GitHub)。 这是我写的一篇旧的代码项目文章

以下是如何使用它来跟踪窗口的大小和位置:

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] 属性。

它具有高度可配置性,您可以配置:
- 当数据被全局或每个跟踪对象保存和应用时
- 它是如何序列化的
- 存储位置(例如文件、数据库、在线、独立存储、注册表)
- 可以取消应用/保留属性数据的规则

相信我,该库是一流的!

I wanted to share a library I've built for this. It's a tiny library, but a big improvement (IMHO) over .settings files.

The library is called Jot (GitHub). Here is an old The Code Project article I wrote about it.

Here's how you'd use it to keep track of a window's size and location:

public MainWindow()
{
    InitializeComponent();

    _stateTracker.Configure(this)
        .IdentifyAs("MyMainWindow")
        .AddProperties(nameof(Height), nameof(Width), nameof(Left), nameof(Top), nameof(WindowState))
        .RegisterPersistTrigger(nameof(Closed))
        .Apply();
}

The benefit compared to .settings files: There's considerably less code, and it's a lot less error-prone since you only need to mention each property once.

With a settings files you need to mention each property five times: once when you explicitly create the property and an additional four times in the code that copies the values back and forth.

Storage, serialization, etc. are completely configurable. When the target objects are created by an IoC container, you can [hook it up][] so that it applies tracking automatically to all objects it resolves, so that all you need to do to make a property persistent is slap a [Trackable] attribute on it.

It's highly configurable, and you can configure:
- when data is persisted and applied globally or for each tracked object
- how it's serialized
- where it's stored (e.g. file, database, online, isolated storage, registry)
- rules that can cancel applying/persisting data for a property

Trust me, the library is top notch!

放低过去 2024-07-19 04:20:52

是的,可以保存配置 - 但这很大程度上取决于您选择的方式。 让我描述一下技术差异,以便您了解您拥有的选项:

首先,您需要区分您是想在 中使用 applicationSettings 还是 AppSettings* .exe.config(在 Visual Studio 中又名 App.config)文件 - 存在根本差异, 此处进行了描述

两者都提供了不同的保存更改的方式:

但是还有其他几个替代选项:

  • 自 .NET Core(以及 .NET 5 和 6)以来)第三个选项appsettings.json 文件,它使用 Microsoft 的配置抽象(以及存储在您的用户中的 secrets.json 文件)配置文件而不是在程序集目录中)。 但通常 WinForms 不使用它,所以我提及它只是为了完整性。 但是,这里有一些参考如何阅读写入值。 或者,您可以使用 Newtonsoft JSON 来读取和写入 appsettings.json 文件,但不限于此:您还可以使用该方法创建自己的 json 文件。

  • 正如问题中提到的,有一个第四个选项:如果您将配置文件视为XML文档,您可以使用以下命令加载、修改和保存它: System.Xml.Linq .XDocument 类。 不需要使用自定义的XML文件,可以读取现有的配置文件; 对于查询元素,您甚至可以使用 Linq 查询。 我在此处给出了一个示例,请查看函数GetApplicationSetting< /code> 答案中有。


  • 第五个选项是将设置存储在注册表中。描述了如何执行此操作这里

  • 最后,还有一个第六个选项:您可以在环境(系统环境或您帐户的环境)中存储值。 在 Windows 设置(Windows 菜单中的齿轮)中,在搜索栏中输入“环境”,然后在其中添加或编辑它们。 要读取它们,请使用
    var myValue = Environment.GetEnvironmentVariable("MyVariable");
    请注意,您的应用程序通常需要重新启动才能获取更新的环境设置。 环境变量不仅限于 Windows,在 Docker 容器中也非常有用。 Microsoft Azure 还可以通过环境变量传递存储在 Azure 中的值。

如果您需要加密来保护您的值,请查看回答。 它描述了如何使用 Microsoft 的 DPAPI 来存储加密的值。

如果您想支持自己的文件(无论是 XML 还是 JSON),那么了解正在运行的程序集的目录可能会很有用:

var assemblyDLL = System.Reflection.Assembly.GetExecutingAssembly();
var assemblyDirectory = System.IO.Path.GetDirectoryName(assemblyDLL.Location);

您可以使用 assemblyDirectory 作为存储文件的基本目录。

Yes, it is possible to save the configuration - but it pretty much depends on the way you choose to do it. Let me describe the technical differences so you can understand the options you have:

First, you need to distinguish, whether you want to use applicationSettings or AppSettings in your *.exe.config(aka App.config in Visual Studio) file - there are fundamental differences, being described here.

Both provide different ways of saving changes:

  • The AppSettings allow you to read and write directly into the config file via config.Save(ConfigurationSaveMode.Modified);, where config is defined as:
    config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
  • The applicationSettings allow to read, but if you write changes (via Properties.Settings.Default.Save();) it will be written on a per-user basis, stored in a special place (e.g. C:\Documents and Settings\USERID\Local Settings\Application Data\FIRMNAME\WindowsFormsTestApplicati_Url_tdq2oylz33rzq00sxhvxucu5edw2oghw\1.0.0.0). As Hans Passant mentioned in his answer, this is because a user usually has restricted rights to Program Files and cannot write to it without invoking the UAC prompt. A disadvantage is if you're adding configuration keys in the future you need to synchronize them with every user profile.

But there are a couple of other alternative options:

  • Since .NET Core (and .NET 5 and 6) a 3rd option is the appsettings.json file which uses Microsoft's configuration abstraction (and also the secrets.json file which is stored in your user profile rather than in the assemblies directories). But usually WinForms isn't using it, so I am mentioning it just for completeness. However, here are some references how to read and write the values. Alternatively you can use Newtonsoft JSON to read and write the appsettings.json file, but it is not limited to that: you can also create your own json files with that method.

  • As mentioned in the question, there is a 4th option: If you treat the configuration file as XML document, you can load, modify and save it by using the System.Xml.Linq.XDocument class. It is not required to use a custom XML file, you can read the existing config file; for querying elements, you can even use Linq queries. I have given an example here, check out the function GetApplicationSetting there in the answer.

  • A 5th option is to store settings in the registry. How you can do it is described here.

  • Last not least, there is a 6th option: You can store values in the environment (system environment or environment of your account). In Windows settings (the cogwheel in the Windows menu), type in "environment" in the search bar and add or edit them there. To read them, use
    var myValue = Environment.GetEnvironmentVariable("MyVariable");.
    Note that your application usually needs to be restarted to get the updated environment settings. Environment variables are not limited to Windows, but quite useful for example in Docker containers as well. And Microsoft Azure can also pass on values stored in Azure via environment variables.

If you require encryption to protect your values, check out this answer. It describes how to use Microsoft's DPAPI to store values encrypted.

And if you want to support your own files, whether XML or JSON, it might be useful to know the directory of the assembly running:

var assemblyDLL = System.Reflection.Assembly.GetExecutingAssembly();
var assemblyDirectory = System.IO.Path.GetDirectoryName(assemblyDLL.Location);

You can use assemblyDirectory as base directory to store your files.

青衫负雪 2024-07-19 04:20:52

registry/configurationSettings/XML 参数似乎仍然非常活跃。 随着技术的进步,我已经使用了所有这些,但我最喜欢的是基于 Threed 系统 结合隔离存储

以下示例允许将名为属性的对象存储到独立存储中的文件中。 例如:

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) { }
        }
    }
}

The registry/configurationSettings/XML argument still seems very active. I've used them all, as the technology has progressed, but my favourite is based on Threed's system combined with Isolated Storage.

The following sample allows storage of an objects named properties to a file in isolated storage. Such as:

AppSettings.Save(myobject, "Prop1,Prop2", "myFile.jsn");

Properties may be recovered using:

AppSettings.Load(myobject, "myFile.jsn");

It is just a sample, not suggestive of best practices.

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) { }
        }
    }
}
中二柚 2024-07-19 04:20:52

一种简单的方法是使用配置数据对象,将其保存为 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>

A simple way is to use a configuration data object, save it as an XML file with the name of the application in the local Folder and on startup read it back.

Here is an example to store the position and size of a form.

The configuration dataobject is strongly typed and easy to use:

[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; }
    }
}

A manager class for saving and loading:

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();
        }
    }
}

Now you can create an instance and use in your form's load and close events:

    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();
    }

And the produced XML file is also readable:

<?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>
橘亓 2024-07-19 04:20:52

“这是否意味着我应该使用自定义 XML 文件来保存配置设置?” 不,不一定。 我们使用 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

"Does this mean that I should use a custom XML file to save configuration settings?" No, not necessarily. We use SharpConfig for such operations.

For instance, if a configuration file is like that

[General]
# a comment
SomeString = Hello World!
SomeInteger = 10 # an inline comment

We can retrieve values like this

var config = Configuration.LoadFromFile("sample.cfg");
var section = config["General"];

string someString = section["SomeString"].StringValue;
int someInteger = section["SomeInteger"].IntValue;

It is compatible with .NET 2.0 and higher. We can create configuration files on the fly and we can save it later.

Source: http://sharpconfig.net/
GitHub: https://github.com/cemdervis/SharpConfig

萌辣 2024-07-19 04:20:52

我不喜欢使用 web.configapp.config 的建议解决方案。 尝试阅读您自己的 XML。 看看XML 设置文件 – 不再有 web.config

I don't like the proposed solution of using web.config or app.config. Try reading your own XML. Have a look at XML Settings Files – No more web.config.

高速公鹿 2024-07-19 04:20:52

其他选项,我们可以使用更用户友好的文件格式:JSON 或 YAML 文件,而不是使用自定义 XML 文件。

  • 如果你使用.NET 4.0动态,这个库真的很容易使用
    (序列化、反序列化、嵌套对象支持和排序输出
    如您所愿+将多个设置合并为一个) JsonConfig (用法相当于ApplicationSettingsBase)
  • 对于 .NET YAML 配置库...我还没有找到这样的库
    易于使用,如 JsonConfig

您可以将设置文件存储在多个特殊文件夹中(针对所有用户和每个用户),如此处所列 Environment.SpecialFolder 枚举 和多个文件(默认只读、每个角色、每个用户等)

如果您选择使用多个设置,则可以合并这些设置:例如,合并 default + BasicUser + AdminUser 的设置。 您可以使用自己的规则:最后一个规则会覆盖该值,等等。

Other options, instead of using a custom XML file, we can use a more user friendly file format: JSON or YAML file.

  • If you use .NET 4.0 dynamic, this library is really easy to use
    (serialize, deserialize, nested objects support and ordering output
    as you wish + merging multiple settings to one) JsonConfig (usage is equivalent to ApplicationSettingsBase)
  • For .NET YAML configuration library... I haven't found one that is as
    easy to use as JsonConfig

You can store your settings file in multiple special folders (for all users and per user) as listed here Environment.SpecialFolder Enumeration and multiple files (default read only, per role, per user, etc.)

If you choose to use multiple settings, you can merge those settings: For example, merging settings for default + BasicUser + AdminUser. You can use your own rules: the last one overrides the value, etc.

厌倦 2024-07-19 04:20:52

据我所知,.NET 确实支持使用内置应用程序设置工具来保存设置:

Windows 窗体的应用程序设置功能可以轻松地在客户端计算机上创建、存储和维护自定义应用程序和用户首选项。 通过 Windows 窗体应用程序设置,您不仅可以存储应用程序数据(例如数据库连接字符串),还可以存储特定于用户的数据(例如用户应用程序首选项)。 使用 Visual Studio 或自定义托管代码,您可以创建新设置、从磁盘读取它们并将其写入磁盘、将它们绑定到表单上的属性,以及在加载和保存之前验证设置数据。
- http://msdn.microsoft.com/en-us/library/k4s6c3a0 .aspx

As far as I can tell, .NET does support persisting settings using the built-in application settings facility:

The Application Settings feature of Windows Forms makes it easy to create, store, and maintain custom application and user preferences on the client computer. With Windows Forms application settings, you can store not only application data such as database connection strings, but also user-specific data, such as user application preferences. Using Visual Studio or custom managed code, you can create new settings, read them from and write them to disk, bind them to properties on your forms, and validate settings data prior to loading and saving.
- http://msdn.microsoft.com/en-us/library/k4s6c3a0.aspx

醉梦枕江山 2024-07-19 04:20:52

有时您想删除保留在传统 web.config 或 app.config 文件中的那些设置。 您希望对设置条目的部署和分离的数据设计进行更细粒度的控制。 或者要求是能够在运行时添加新条目。

我可以想象两个不错的选择:

  • 强类型版本和
  • 面向对象版本。

强类型版本的优点是强类型设置名称和值。 不存在混合名称或数据类型的风险。 缺点是需要编写更多设置,无法在运行时添加。

面向对象版本的优点是可以在运行时添加新设置。 但是您没有强类型的名称和值。 必须小心字符串标识符。 获取值时必须知道之前保存的数据类型。

您可以在此处找到这两个功能齐全的实现的代码。

Sometimes you want to get rid of those settings kept in the traditional web.config or app.config file. You want more fine grained control over the deployment of your settings entries and separated data design. Or the requirement is to enable adding new entries at runtime.

I can imagine two good options:

  • The strongly typed version and
  • The object oriented version.

The advantage of the strongly typed version are the strongly typed settings names and values. There is no risk of intermixing names or data types. The disadvantage is that more settings have to be coded, cannot be added at runtime.

With the object oriented version the advantage is that new settings can be added at runtime. But you do not have strongly typed names and values. Must be careful with string identifiers. Must know data type saved earlier when getting a value.

You can find the code of both fully functional implementations HERE.

顾北清歌寒 2024-07-19 04:20:52
public static class SettingsExtensions
{
    public static bool TryGetValue<T>(this Settings settings, string key, out T value)
    {
        if (settings.Properties[key] != null)
        {
            value = (T) settings[key];
            return true;
        }

        value = default(T);
        return false;
    }

    public static bool ContainsKey(this Settings settings, string key)
    {
        return settings.Properties[key] != null;
    }

    public static void SetValue<T>(this Settings settings, string key, T value)
    {
        if (settings.Properties[key] == null)
        {
            var p = new SettingsProperty(key)
            {
                PropertyType = typeof(T),
                Provider = settings.Providers["LocalFileSettingsProvider"],
                SerializeAs = SettingsSerializeAs.Xml
            };
            p.Attributes.Add(typeof(UserScopedSettingAttribute), new UserScopedSettingAttribute());
            var v = new SettingsPropertyValue(p);
            settings.Properties.Add(p);
            settings.Reload();
        }
        settings[key] = value;
        settings.Save();
    }
}
public static class SettingsExtensions
{
    public static bool TryGetValue<T>(this Settings settings, string key, out T value)
    {
        if (settings.Properties[key] != null)
        {
            value = (T) settings[key];
            return true;
        }

        value = default(T);
        return false;
    }

    public static bool ContainsKey(this Settings settings, string key)
    {
        return settings.Properties[key] != null;
    }

    public static void SetValue<T>(this Settings settings, string key, T value)
    {
        if (settings.Properties[key] == null)
        {
            var p = new SettingsProperty(key)
            {
                PropertyType = typeof(T),
                Provider = settings.Providers["LocalFileSettingsProvider"],
                SerializeAs = SettingsSerializeAs.Xml
            };
            p.Attributes.Add(typeof(UserScopedSettingAttribute), new UserScopedSettingAttribute());
            var v = new SettingsPropertyValue(p);
            settings.Properties.Add(p);
            settings.Reload();
        }
        settings[key] = value;
        settings.Save();
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文