Tom Haigh
Tom Haigh

Reputation: 57835

Can I modify [appname].exe.config without having to manually read/write the XMl?

I have created some settings in a C# application using .NET 3.5 and Visual Studio 2008 Express. I have a number of application-scoped settings which I would like to be able to modify from within the application - I can access them through Properties.Settings.Default but they are read only as expected. I do not want to have to make these become user-scoped settings as they should be application-wide. Is this possible without loading the XML and reading/writing from/to it myself?

I have seen examples using System.Configuration.ConfigurationManager.OpenExeConfiguration, but the config xml looks to be in a different format to that which I am using (is this from an older version?)

Thanks


Edit

I worked out that I can modify the values doing this, but it seems like a ridiculous hack.

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

Upvotes: 4

Views: 6941

Answers (2)

Cheeso
Cheeso

Reputation: 192587

You could also use the Windows Registry to store app-specific state. There are per-user and per-machine keys in the registry - either or both are available to you . For example, some people use the registry to store the location and size of the app window upon exit. Then when the app is restarted, you can position and size the window according to its last known size. This is a small example of the sort of state you can store in the registry.

To do it you would use different APIs for storage and retrieval. Specifically the SetValue and GetValue calls on the Microsoft.Win32.RegistryKey class. There may be libraries that are helpful in persisting complex state to the registry. If you have simple cases ( a few strings and numbers) then it is easy to just do it yourself.

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

That code uses Microsoft.Win32.Registry.CurrentUser, and so it sets and retrieves user-specific app settings. If you are setting or retrieving machine-wide state, you want Microsoft.Win32.Registry.LocalMachine.

Upvotes: 1

Ronald Wildenberg
Ronald Wildenberg

Reputation: 32134

OpenExeConfiguration (or any of the other ConfigurationManager methods) is the preferred entry point for most modifications to configuration files. Once you have a Configuration instance you should get the section you wish to modify and after the modifications call any of the ConfigurationManager.Save methods. However, it is impossible to retrieve the applicationSettings section this way.

There is no API for changing settings from the applicationSettings section in your app.config file. Only user-scoped settings can be changed this way.

So actually changing these settings can only be done by directly manipulating the app.config XML file.

Some confusion may occur because the indexed property from Properties.Settings.Default is actually writable. The following is perfectly legal:

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

However, the setting will not be saved.

Upvotes: 1

Related Questions