Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / XML

XML Application Settings

2.60/5 (5 votes)
15 Jun 2021CPOL3 min read 8.7K   116  
Save and retrieve user settings for your application in an XML file
This tip demonstrates the use of a class library for saving and retrieving data from an XML file.

article

Introduction

This tip will demonstrate the use of a simple static class library for saving and retrieving user settings data within an XML file. The image above is the XML file content format; a single node deep structure for storing key/value pairs.

Implementation

C#
//
// Specify settings and initial values
//---------------------------------------------------------

StringCollection settings = new StringCollection();

// First value = Setting name
// Second value = Initial value
// Values are separated with a comma

settings.Add("BorderNone,True");
settings.Add("BorderSingle,False");
settings.Add("Border3D,False");
settings.Add("PictureBoxBackColor,#F0F0F0");

XMLSettings.AppSettingsFile = "Settings.xml"; // Set the file path
XMLSettings.InitializeSettings(settings);     // Create file and set initial values

//----------------------------------------------------------

// Read settings values

rbNone.Checked = bool.Parse(XMLSettings.GetSettingsValue("BorderNone"));
rbBorderSingle.Checked = bool.Parse(XMLSettings.GetSettingsValue("BorderSingle"));
rbBorder3D.Checked = bool.Parse(XMLSettings.GetSettingsValue("Border3D"));
txtColor.Text = XMLSettings.GetSettingsValue("PictureBoxBackColor");

// Set settings values

XMLSettings.SetSettingsValue("BorderNone", rbNone.Checked.ToString());
XMLSettings.SetSettingsValue("BorderSingle", rbBorderSingle.Checked.ToString());
XMLSettings.SetSettingsValue("Border3D", rbBorder3D.Checked.ToString());
XMLSettings.SetSettingsValue("PictureBoxBackColor", txtColor.Text);

Basic Principles

There are three methods and a string that you will use below.

Specify where you want the settings file to be saved for your application.

C#
public static string AppSettingsFile

InitializeSettings() takes a StringCollection object, creates the settings file in the location specified and adds the settings with their initial values.

C#
public static void InitializeSettings(StringCollection _AppSettings)

Specify the setting you want to update and its new value.

C#
public static void SetSettingsValue(string _Field, string _Value)

Retrieve a specific setting and its current value.

C#
public static string GetSettingsValue(string _Field)

Under the Hood

All code exists in XMLSettings.cs. It utilizes the System.Xml, and System.Collections.Specialized namespaces.

Starting at the top of the file...

SettingsFileExists

SettingsFileExists() is a simple helper method for checking whether the settings file already exists. Used in InitializeSettings().

C#
private static bool SettingsFileExists()
{
      bool flag = false;

      if (File.Exists(AppSettingsFile))
            flag = true;
      else
            flag = false;

      return flag;
}

GetSettingsValue

GetSettingsValue() utilizes the XmlDocument object to load the contents of the file. Once the file is loaded, we use the XmlNode object and the SelectSingleNode() method to locate the setting that we want to read the value of. The InnerText property of the XmlNode object is used to retrieve the value of the specifed setting.

C#
public static string GetSettingsValue(string _Field)
{
      XmlDocument doc = new XmlDocument();
      doc.Load(AppSettingsFile);

      XmlNode node = null;
      node = doc.SelectSingleNode("//Settings/" + _Field);

      string value = string.Empty;

      if (node == null)
            value = string.Empty;
      else
            value = node.InnerText;

      return value;
}

SetSettingsValue

As with GetSettingsValue() above, SetSettingsValue() loads the contents of the file. We then attempt to select an XmlNode from the document. If none exist with the name provided, we create a new setting with the XmlDocument.CreateElement() method and add it to the file with XmlDocument.DocumentElement.AppendChild(). Once the setting has been added, we then Save() the document. If an XmlNode with the name provided does exist, we just assign a new value to the InnerText property and then Save() the document.

C#
public static void SetSettingsValue(string _Field, string _Value)
{
      XmlDocument doc = new XmlDocument();
      doc.Load(AppSettingsFile);

      _Field = "//Settings/" + _Field;

      if (doc.SelectSingleNode(_Field) == null)
      {
            _Field = _Field.Replace("//Settings/", "");
            XmlNode field = doc.CreateElement(_Field);
            field.InnerText = _Value;
            doc.DocumentElement.AppendChild(field);
            doc.Save(AppSettingsFile);
      }
      else
      {
            XmlNode node = null;
            node = doc.SelectSingleNode(_Field);
            node.InnerText = _Value;
            doc.Save(AppSettingsFile);
      }
}

InitializeSettings

InitializeSettings() does a few basic things. First, it checks whether or not the settings file exists. If it does not, it will create the file, loop through all the settings in the StringCollection and add them to the file. If the file does exist, it will check to see if there have been any new settings added to the StringCollection, and add the ones that don't exist in the file and set the initial value.

C#
public static void InitializeSettings(StringCollection _AppSettings)
{
    if (!SettingsFileExists())
    {
        XmlWriterSettings settings = new XmlWriterSettings();
        settings.Indent = true;
        XmlWriter XmlWrt = XmlWriter.Create(AppSettingsFile, settings);

        {
            var withBlock = XmlWrt;
            withBlock.WriteStartDocument();

            withBlock.WriteComment("Application Settings");
            withBlock.WriteStartElement("Settings");

            string[] arr;

            foreach (string setting in _AppSettings)
            {
                arr = setting.Split(',');

                string settingName = arr[0];
                string defaultValue = arr[1];

                withBlock.WriteStartElement(settingName);
                withBlock.WriteString(defaultValue);
                withBlock.WriteEndElement();
            }

            withBlock.WriteEndDocument();
            withBlock.Close();
        }

        XmlWrt = null;
    }
    else
    {
        XmlDocument xmlDoc = new XmlDocument();

        xmlDoc.Load(AppSettingsFile);
        XmlElement elm = xmlDoc.DocumentElement;
        XmlNodeList lstSettings = elm.ChildNodes;
        string[] arr;
        StringCollection nodeNames = new StringCollection();

        foreach (XmlNode node in lstSettings)
        {
            nodeNames.Add(node.Name);
        }

        foreach (string setting in _AppSettings)
        {
            arr = setting.Split(',');

            string settingName = arr[0];
            string defaultValue = arr[1];

            if (!nodeNames.Contains(settingName))
            {
                XmlNode newSetting = xmlDoc.CreateElement(settingName);
                newSetting.InnerText = defaultValue;
                xmlDoc.DocumentElement.AppendChild(newSetting);
                xmlDoc.Save(AppSettingsFile);
            }
        }
    }
}

Conclusion

I wanted to write a simple class that I could use in my applications to store user settings, however, after using it and writing this article, I would like to improve the following items:

  • Revise code to eliminate using a StringCollection with values separated by a comma. I currently have not run into any issues with the implementation considering I have always hand coded these values, however handling commas can be a hassle. I will explore using a Dictionary. Recommendations are welcome in the comments.
  • Figure out a way to dynamically create an enum based on the settings that are in the file to eliminate potential errors due to spelling mistakes. Perhaps a Dictionary will also help with this.

Comments and recommendations for improvement are welcome. Thanks for reading!

History

  • 15th June, 2021: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)