62

我有一个 .NET 2.0 Windows 窗体应用程序。商店用户设置的最佳位置在哪里(考虑 Windows 指南)?

有人指着Application.LocalUserAppDataPath。但是,这会创建一个文件夹结构,例如:

C:\Documents and Settings\user_name\Local Settings\Application Data\company_name\product_name\product_version\

如果我发布我的应用程序的版本 1 并在那里存储一个 XML 文件,然后发布版本 2,那将更改为不同的文件夹,对吗?无论应用程序版本如何,我都希望每个用户都有一个文件夹来存储设置。

4

8 回答 8

85

我喜欢使用内置的应用程序设置。然后,如果您想在设计时或运行时使用设置设计器,那么您已经内置了支持:

// read setting
string setting1 = (string)Settings.Default["MySetting1"];
// save setting
Settings.Default["MySetting2"] = "My Setting Value";

// you can force a save with
Properties.Settings.Default.Save();

它确实将设置存储在您描述的类似文件夹结构中(路径中的版本)。但是,通过一个简单的调用:

Properties.Settings.Default.Upgrade(); 

该应用程序将拉入所有以前的版本设置以保存。

于 2008-08-25T16:59:15.527 回答
9

.NET 应用程序具有易于使用的内置设置机制。在我看来,它的问题在于它将这些设置存储到一个相当模糊的目录中,最终用户将无法找到它。此外,只是从调试切换到发布构建会更改此目录的位置,这意味着保存在一个配置中的任何设置都会丢失在另一个配置中。

由于这些和其他原因,我想出了自己的 Windows Forms 设置代码。它不像 .NET 附带的那样流畅,但更灵活,我一直都在使用它。

于 2011-03-21T15:00:38.903 回答
5

或者将您的设置写入 xml 文件并使用独立存储进行保存。根据您使用的商店,它会将其保存在 Application Data 文件夹中。您还可以选择启用漫游的存储,这意味着当用户登录另一台计算机时,设置会随之移动。

于 2008-08-25T17:11:33.080 回答
2

过去对我有用的一种方法是创建一个设置类并使用 XML 序列化将其写入文件系统。您可以通过创建一组设置对象并将其序列化来扩展此概念。您可以将所有用户的所有设置集中在一个地方,而不必担心管理文件系统。

在有人批评我部分重新发明轮子之前,让我说几句话。其一,序列化和写入文件只需几行代码。其次,如果您有一个包含设置的对象,则在加载应用程序时不必多次调用 appSettings 对象。最后,很容易添加代表应用程序状态的项目,从而允许您在应用程序下次加载时恢复长时间运行的任务。

于 2008-08-25T17:06:26.650 回答
1

我尝试了一些方法将我的设置存储到简单的文本文件中,我找到了最好的方法:

存储在应用程序文件夹中的文件,用于使用,settings.txt:(在设置文件中批准评论,尝试//评论)

//获取设置值

Settings.Get("name", "Ivan");

//设置设置值

Settings.Set("name", "John");

使用:

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;

//你也可以存储部分名称,使用只需添加名称部分 Set(section_name,name,value) 和 Get(section_name,name,value)

public static class Settings
{
    private static string SECTION =  typeof(Settings).Namespace;//"SETTINGS";
    private static string settingsPath = Application.StartupPath.ToString() + "\\settings.txt";
    [DllImport("kernel32")]
    private static extern long WritePrivateProfileString(string section, string key, string val, string filePath);
    [DllImport("kernel32")]
    private static extern int GetPrivateProfileString(string section, string key, string def, StringBuilder retVal, int size, string filePath);
    public static String GetString(String name)
    {
        StringBuilder temp = new StringBuilder(255);
        int i = GetPrivateProfileString(SECTION,name,"",temp,255,settingsPath);
        return temp.ToString();
    }
    public static String Get(String name, String defVal)
    {
        return Get(SECTION,name,defVal);
    }
    public static String Get(string _SECTION, String name, String defVal)
    {
        StringBuilder temp = new StringBuilder(255);
        int i = GetPrivateProfileString(_SECTION, name, "", temp, 255, settingsPath);
        return temp.ToString();
    }
    public static Boolean Get(String name, Boolean defVal)
    {
        return Get(SECTION, name, defVal);
    }
    public static Boolean Get(string _SECTION, String name, Boolean defVal)
    {
        StringBuilder temp = new StringBuilder(255);
        int i = GetPrivateProfileString(_SECTION,name,"",temp,255,settingsPath);
        bool retval=false;
        if (bool.TryParse(temp.ToString(),out retval))
        {
            return retval;
        } else
        {
            return retval;
        }
    }
    public static int Get(String name, int defVal)
    {
        return Get(SECTION, name, defVal);
    }
    public static int Get(string _SECTION, String name, int defVal)
    {
        StringBuilder temp = new StringBuilder(255);
        int i = GetPrivateProfileString(SECTION,name,"",temp,255,settingsPath);
        int retval=0;
        if (int.TryParse(temp.ToString(),out retval))
        {
            return retval;
        } else
        {
            return retval;
        }
    }
    public static void Set(String name, String val)
    {
        Set(SECTION, name,val);
    }
    public static void Set(string _SECTION, String name, String val)
    {
        WritePrivateProfileString(_SECTION, name, val, settingsPath);
    }
    public static void Set(String name, Boolean val)
    {
        Set(SECTION, name, val);
    }
    public static void Set(string _SECTION, String name, Boolean val)
    {
        WritePrivateProfileString(_SECTION, name, val.ToString(), settingsPath);
    }
    public static void Set(String name, int val)
    {
        Set(SECTION, name, val);
    }
    public static void Set(string _SECTION,String name, int val)
    {
        WritePrivateProfileString(SECTION, name, val.ToString(), settingsPath);
    }
}
于 2015-06-25T08:02:30.147 回答
0

设置是标准的键值对(字符串-字符串)。如果有帮助,我可以将它们包装在 XML 文件中。

我宁愿使用文件系统而不是注册表。它似乎更容易维护。在支持场景中,如果用户需要手动打开/更改设置,如果它在文件系统中会更容易。

于 2008-08-25T16:48:37.177 回答
0

除了产品版本之外,我会查看您发布的文件夹列表。您不希望在发布更新后重置设置。

由于调试/占用空间因素,我实际上正在远离用户设置的注册表。我目前只在注册表中存储了一些基本设置(窗口大小、位置、数据文件的版本),如果更新出错或用户丢失第二台显示器,我会遇到更多问题,这就是该应用程序正在打开。他们中的一些人足够精明,可以理解 regedit,但对于其余的人来说,他们必须重新安装,这很快,但我认为他们有点抱怨。对于基于文件的版本,我所要做的就是让他们在记事本中打开一个 XML 文件并进行快速调整。

此外,我希望使我的应用程序可以在 USB 闪存驱动器上运行,并且将设置绑定到文件中似乎对该过程更友好。我确信我可以编写一些代码来检查/清理注册表,但我认为我们大多数人已经厌倦了现在似乎吞噬我们机器的注册表混乱。

我知道对此有一些安全性权衡,但我正在排序的所有数据都不是对这个原因至关重要的,而且由于应用程序的大小,我没有遭受任何性能损失。

于 2008-08-25T16:50:22.287 回答
0

隔离存储主要用于使用ClickOnce分发的应用程序,并在安全沙箱中运行。基本路径是为您决定的,您将无法在代码中推断它。路径类似于“\LocalSettings\ApplicationData\IsolatedStorage\ejwnwe.302\kfiwemqi.owx\url.asdaiojwejoieajae....”,并不是那么友好。您的存储空间也有限。

瑞恩法利说得对

于 2008-08-25T21:45:05.450 回答