【问题标题】:Can I modify [appname].exe.config without having to manually read/write the XMl?我可以修改 [appname].exe.config 而无需手动读取/写入 XMl 吗?
【发布时间】:2009-05-16 19:10:54
【问题描述】:

我使用 .NET 3.5 和 Visual Studio 2008 Express 在 C# 应用程序中创建了一些设置。我有许多应用程序范围的设置,我希望能够从应用程序中修改它们 - 我可以通过 Properties.Settings.Default 访问它们,但它们按预期只读。我不想让这些成为用户范围的设置,因为它们应该是应用程序范围的。如果不加载 XML 并自己读取/写入它,这是否可能?

我已经看到使用 System.Configuration.ConfigurationManager.OpenExeConfiguration 的示例,但配置 xml 看起来与我使用的格式不同(这是来自旧版本吗?)

谢谢


编辑

我发现我可以这样做修改值,但这似乎是一个荒谬的黑客攻击。

Configuration config = ConfigurationManager.OpenExeConfiguration(Application.ExecutablePath);
SettingElementCollection settingElements = ((ClientSettingsSection)config.GetSectionGroup("applicationSettings").Sections[0]).Settings;

SettingElement element = settingElements.Get("SettingName");
element.Value.ValueXml.InnerText = "new value";

config.Save(ConfigurationSaveMode.Modified, true);

【问题讨论】:

    标签: c# .net


    【解决方案1】:

    OpenExeConfiguration(或任何其他ConfigurationManager 方法)是对配置文件进行大多数修改的首选入口点。一旦你有一个Configuration 实例,你应该得到你想要修改的部分,并在修改后调用任何ConfigurationManager.Save 方法。但是,这种方式无法检索到applicationSettings 部分。

    app.config 文件中的applicationSettings 部分没有用于更改设置的 API。这种方式只能更改用户范围的设置。

    所以实际更改这些设置只能通过直接操作 app.config XML 文件来完成。

    可能会出现一些混淆,因为来自Properties.Settings.Default 的索引属性实际上是可写的。以下是完全合法的:

    Properties.Settings.Default["MySetting"] = "New setting value";
    Properties.Settings.Default.Save();
    

    但是,设置不会被保存。

    【讨论】:

    • 并记住允许对配置文件的权限。预计 app.exe.config 只能写入管理员。
    • 谢谢。为了获得 Properties.Settings.Default 中的设置,我需要什么部分?
    • 我知道我没有很好地阅读您的问题。我建议的方法是对配置文件进行一般更改。我更新了我的答案以展示另一种(更好的)方法来更改程序集范围的设置。
    • 嗯,它似乎没有将更改写回文件。但也许我太厚了
    • 好吧,看来我搞错了,抱歉。经过进一步研究,我发现如果不直接操作 xml,就无法保存应用程序范围的设置。
    【解决方案2】:

    您还可以使用 Windows 注册表来存储应用特定的状态。注册表中有每个用户和每个机器的密钥 - 您可以使用其中一个或两个。例如,有些人在退出时使用注册表来存储应用程序窗口的位置和大小。然后,当应用程序重新启动时,您可以根据上次已知的大小来定位和调整窗口大小。这是您可以在注册表中存储的那种状态的一个小例子。

    为此,您将使用不同的 API 进行存储和检索。特别是 Microsoft.Win32.RegistryKey 类上的 SetValue 和 GetValue 调用。可能有一些库有助于将复杂状态保存到注册表。如果您有简单的案例(一些字符串和数字),那么您自己就可以轻松完成。

      private static string _AppRegyPath = "Software\\Vendor Name\\Application Name";
    
      public Microsoft.Win32.RegistryKey AppCuKey
      {
          get
          {
              if (_appCuKey == null)
              {
                  _appCuKey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(_AppRegyPath, true);
                  if (_appCuKey == null)
                      _appCuKey = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(_AppRegyPath);
              }
              return _appCuKey;
          }
          set { _appCuKey = null; }
      }
    
    
      private void RetrieveAndApplyState()
      { 
          string s = (string)AppCuKey.GetValue("textbox1Value");
          if (s != null) this.textbox1.Text = s;
    
          s = (string)AppCuKey.GetValue("Geometry");
          if (!String.IsNullOrEmpty(s))
          {
              int[] p = Array.ConvertAll<string, int>(s.Split(','),
                               new Converter<string, int>((t) => { return Int32.Parse(t); }));
              if (p != null && p.Length == 4)
              {
                  this.Bounds = ConstrainToScreen(new System.Drawing.Rectangle(p[0], p[1], p[2], p[3]));
              }
          }
      }
    
      private void SaveStateToRegistry()
      {
          AppCuKey.SetValue("textbox1Value", this.textbox1.Text);
    
          int w = this.Bounds.Width;
          int h = this.Bounds.Height;
          int left = this.Location.X;
          int top = this.Location.Y;
    
          AppCuKey.SetValue("Geometry", String.Format("{0},{1},{2},{3}", left, top, w, h);
      }
    
    
      private System.Drawing.Rectangle ConstrainToScreen(System.Drawing.Rectangle bounds)
      {
          Screen screen = Screen.FromRectangle(bounds);
          System.Drawing.Rectangle workingArea = screen.WorkingArea;
          int width = Math.Min(bounds.Width, workingArea.Width);
          int height = Math.Min(bounds.Height, workingArea.Height);
          // mmm....minimax            
          int left = Math.Min(workingArea.Right - width, Math.Max(bounds.Left, workingArea.Left));
          int top = Math.Min(workingArea.Bottom - height, Math.Max(bounds.Top, workingArea.Top));
          return new System.Drawing.Rectangle(left, top, width, height);
      }
    

    该代码使用 Microsoft.Win32.Registry.CurrentUser,因此它设置和检索用户特定的应用设置。如果要设置或检索计算机范围的状态,则需要 Microsoft.Win32.Registry.LocalMachine。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-05
      • 1970-01-01
      • 2015-08-04
      • 2011-01-17
      • 2016-12-05
      • 1970-01-01
      相关资源
      最近更新 更多