Click here to Skip to main content
15,885,546 members
Articles / Programming Languages / XML
Article

Saving app settings as XML

Rate me:
Please Sign up or sign in to vote.
4.64/5 (35 votes)
24 Apr 2007CPOL7 min read 185K   3.2K   156   46
Saving application settings to XML.

Sample Image

Introduction

This is my first article. I hope that my code and findings are helpful to other members of The Code Project. Much of this work was done as a learning experience. Did my best to comment the code to support NDoc.

Most of my programs are small utilities with just a few settings that I would like to persist. Things like the items in a ListBox or the selections made in a TreeView etc...

In the past, I have used the Win32 WritePrivateProfileString, GetPrivateProfileString or a file of my own making. So when it was time to learn .NET, one of the first things I wanted was a simple way to save my settings. When I didn't find what I wanted, I decided to write a DLL to use in all my programs. My first impression with the .NET Framework was how extensive it was. So I hope I haven't re-invented a wheel here.

My options to save settings seemed to be:

  • Use Win32 API.
    • Pro: Simple, human readable format (text).
    • Con: 16 Bit, requires interop, limited structure.
  • The AppSettingsReader class.

    Seems like a good solution for some things but did not suit all my needs.

    • Pro: Simple, human readable format (XML).
    • Con: Casting is required on returned values.
  • Use the system registry.
    • Pro: Can't think of one.
    • Con: Too dangerous. Plus the settings are not as easily moved around.

    I don't like to mess with other people's registries. If I need to have a customer make an edit to a setting for some reason, they will have to use Regedit.

  • Use XML Serialization. Seemed like a good option at first, but I decided against it. I will explain later.
    • Pro: Simple, human readable format (XML).
    • Con: Casting is required because I am storing my settings in objects.

    This may become a better solution with the new .NET 2.0.

  • Roll my own.
    • Pro: The great thing about writing your own is when it stops working... you can fix it.
    • Con: Writing your own code.

The Code Project was the first place I looked for some help on this topic and I found lots of it. Much of it used the XmlSerializer. After working with this class a bit, it seemed a little overkill so I decided not to use it. The XmlSerializer seems to take a while to load and still did not handle all my data types the way I wanted (like Color). If I knew the exact structure and type of my data at design time, it may be a good solution.

Because the user may want to save many different data types, it seemed that an

C#
Object
type was the way to go. Normally, I would never even think of using an Object, but speed is not an issue here.

The trouble with the Object is all that casting. Having the user (me) explicitly cast the return value each time would be a pain.

Example

C#
int ret = (int)MyIni.Sections["FormSettings"]["Left"];

The plan was to determine the data type when the user sets the value, and then save that type in the XML file. Then when you read the data back, just use an implicit cast to return it to the original type.

Example

C#
int ret = MyIni.Sections["FormSettings"]["Left"];

Normally, an implicit cast is a bad thing. Implicit conversions can occur without the programmer specifying them, so care must be taken to prevent unpleasant surprises. In this case, we know the original type because we saved it when we set the value. So it seems safe. Plus, you could always get to the original Object by using the "Value" property of the setting.

Example

C#
object ret = MyIni.Sections["FormSettings"]["Left"].Value;

Having said that, with the new Generics feature, this may change. Generics are a new feature in version 2.0 of the C# language and the common language runtime (CLR). They are somewhat like Class Templates in C++.

This is a sample of one of the overloaded operators to cast to bool. If you try to set a value of a type different than the original, it will throw an error.

C#
public static implicit operator bool(IniSetting v)
{
    if(v.settingType!=Types.BOOLEAN)
    {
     throw new Exception("No conversion from " + v.settingType + " to bool." );
    }
    return (bool)v.settingValue;
}

Using the code

AppSettings class has the following members:

  • AppSettings() - Constructor, without a file specified. You will have to specify one with the Save method.
  • AppSettings(string fileName) - Constructor, with file name specified. Just simply use the Save method with no file name.
  • bool Load() - Loads the settings from disk using the default file.
  • bool Load(string filename) - Loads the settings from disk using a specified file.
  • C#
    IniSetting GetVal(string sectionName, string settingName,object 
                        oDefault)
    - Read a value. Created on-demand.
  • C#
    IniSetting SetVal(string sectionName, string settingName, object 
                        oValue)
    - Set/create a value.
  • C#
    IniSetting SetVal(string sectionName, string settingName, object 
                        oValue, string description)
    - Set/create a value.
  • void Remove(string sectionName, string settingName) - Remove a setting by name.
  • void Remove(string sectionName) - Remove a section by name.
  • bool Save() - Save settings to file specified in constructor.
  • bool Save(string pathAndFileName) - Save settings to specific file.

To use the DLL, just make a reference to it and use the following syntax:

C#
//Try to load the settings bool loaded = MyIni.Load([File]); 
//Get the color of the form. It will be created 
//only if needed, using the current value. 
BackColor = MyIni.GetVal("FormSettings","BackColor",BackColor); 
//Font of the form. It will be created only if needed. 
Font = MyIni.GetVal("FormSettings","Font",Font); 
//Size of the form. It will be created only if needed 
Size = MyIni.GetVal("FormSettings","Size",Size);
//Notice in the following code that we do not have to cast the return value;
MyIni.SetVal("FormSettings","Left",Left);
//Return the same value with 2 different notations.
int ret = MyIni.GetVal("FormSettings","Left");
ret = MyIni.Sections["FormSettings"]["Left"];
//Save the settings
MyIni.Save([File]);

After the core functionality was finished, a utility class was created to handle more complicated settings. The overloaded methods

C#
static bool 
                SaveItemsAndValues
and static bool LoadItemsAndValues were added. It currently supports ComboBox, ListBox and TreeView. Sample code is provided for each.

At this point, the functionality is much like the old INI files. You have to write code to read each setting when a form is opened, and then write code to save the settings when the form is closed. That's not too bad but it could be better.

The ability to mark a particular property to be saved and add it to a list would be cool. That way, you could just tell the program to save all the marked properties when you close the form. You could use "Dynamic Properties" to save the settings to the app.config file but I chose not to interfere with that built-in functionality.

Somehow, I needed to save a reference to a control and one of its properties. Saving the name of a control and a property to XML is no problem. Getting a reference to an instance of a control at run time was the problem. This was done with Reflection. In case Reflection is new to you (it was (is) to me), Reflection provides a way to discover everything about an assembly or module. It also provides a way to do late binding and to invoke a method dynamically. This is what I needed. These are the static methods that achieve this.

  • AddPropertyToBag(MyIni,tbTest,"Text"); Sets the propertied to be persisted. A "PropertyBag" section is created.
  • SaveAllPropertiesInBag(MyIni, this); Saves all persisted properties for all controls.
  • SetAllPropertiesFromBag(MyIni, this); Loads properties for any persisted control properties on this parent control.

Points of Interest

The PropertyGrid support was created with lots of help from CP contributors. I only have a basic understanding of the mechanism. The PropertyGrid will be a great interface for editing values.

The code uses #region PropertyGrid Support to identify code specific to the PG. Other than that, there are two extra PropertyDescriptor classes to support collections in the PG. Any suggestions for better PropertyGrid support is welcome.

Resources Used

History

  • V1.0.1.1
    • This is the initial release of this DLL and I expect trouble until I can do some thorough testing.
  • V1.0.2.3
    • Fixed a bug that prevented Single types from working.
    • Re-wrote the reader to use the XmlTextReader class because we don't need the DOM and it should be faster.
    • Changed the XML structure to reduce the file size.
    • Added support for Encryption.
  • V1.0.2.3
    • Added properties to allow you to hide or disable settings and sections in the
      PropertyGrid
      
      .
    • Fixed some typos in the comments based on user feedback.
    • Added globalization of some setting types based on user feedback.
    • Cleaned up the test form a little.
  • V1.0.2.9
    • Fixed a problem where empty sections caused read failure.
    • Fixed a problem where manually entered xml comments caused read failure.
    • Fixed a problem where XmlComments property was infinitly recursive.

Running the test program

  1. Start the program and click LoadTestData.
  2. Check some items in the tree and make some other changes.
  3. Click SaveCtrlsToSettings. This saves the tree and combo to the settings but not to disk.
  4. Click SaveSettingsToDisk. This saves the settings to disk.
  5. Close the program.
  6. Start the program and click LoadSettingsFromDisk. You should see your settings come back.
  7. Click LoadJasonsSettings. You should see My sample settings.

License

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


Written By
Web Developer
United States United States
Currently working as a CAD(Computer aided design) trainer and macro developer for a CAD company. Background also includes 8 years of CNC(computer numerical control) programming and machine tool automation.

Comments and Discussions

 
QuestionProblem with Setting Type Pin
Z@clarco22-Jan-16 2:31
Z@clarco22-Jan-16 2:31 
GeneralThanks for all the hard work! Pin
bobishkindaguy17-Dec-10 15:43
bobishkindaguy17-Dec-10 15:43 
GeneralRe: Thanks for all the hard work! Pin
Jason Titcomb18-Dec-10 2:36
Jason Titcomb18-Dec-10 2:36 
GeneralRe: Thanks for all the hard work! Pin
bobishkindaguy21-Dec-10 0:43
bobishkindaguy21-Dec-10 0:43 
Generalhelp for my cnc projectt Pin
raheel1897-Nov-09 3:51
raheel1897-Nov-09 3:51 
QuestionCould you tell me what license your code is released under? Pin
Noobsa4416-Aug-09 12:58
Noobsa4416-Aug-09 12:58 
AnswerRe: Could you tell me what license your code is released under? Pin
Jason Titcomb22-Aug-09 1:26
Jason Titcomb22-Aug-09 1:26 
GeneralSuggested fix in Settings.cs Pin
Giuseppe Bondi5-Jul-08 18:48
Giuseppe Bondi5-Jul-08 18:48 
QuestionHow did you get the Property Grid to Nest Pin
Luckymmkay14-Dec-07 10:39
Luckymmkay14-Dec-07 10:39 
AnswerRe: How did you get the Property Grid to Nest Pin
ByteGhost23-Dec-07 15:02
ByteGhost23-Dec-07 15:02 
GeneralXML Serialization Pin
BoneSoft1-May-07 9:43
BoneSoft1-May-07 9:43 
GeneralSuggested fix Pin
curiousharry17-Apr-07 8:25
curiousharry17-Apr-07 8:25 
GeneralRe: Suggested fix Pin
Jason Titcomb20-Apr-07 11:38
Jason Titcomb20-Apr-07 11:38 
QuestionBug in AppSettings Pin
DIWIN5-Feb-07 23:22
professionalDIWIN5-Feb-07 23:22 
AnswerRe: Bug in AppSettings Pin
Jason Titcomb20-Apr-07 11:47
Jason Titcomb20-Apr-07 11:47 
GeneralSmall Bug in AppSettings Pin
gbalog8-Nov-06 23:59
gbalog8-Nov-06 23:59 
GeneralError in loading settings that contain enumeration types Pin
Xezerox19-Jun-06 9:58
Xezerox19-Jun-06 9:58 
GeneralRe: Error in loading settings that contain enumeration types Pin
mad-matt31-Mar-09 9:29
mad-matt31-Mar-09 9:29 
GeneralPro for Registry Settings Pin
Timothy19-Jun-06 8:58
Timothy19-Jun-06 8:58 
Generalanother ready-to-use solution Pin
Edwin Roetman20-Mar-06 23:33
Edwin Roetman20-Mar-06 23:33 
Generalthanks Pin
CalvinHobbies18-Mar-06 8:39
CalvinHobbies18-Mar-06 8:39 
GeneralAnother fix and another typo Pin
Perry27-Mar-06 4:39
Perry27-Mar-06 4:39 
Questionoutstanding bugs? Pin
Perry27-Mar-06 4:22
Perry27-Mar-06 4:22 
AnswerRe: outstanding bugs? Pin
Jason Titcomb12-Mar-06 2:14
Jason Titcomb12-Mar-06 2:14 
GeneralPortability of SaveSettingsToXml files across locales Pin
Fred Thomas21-Aug-05 4:46
Fred Thomas21-Aug-05 4:46 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.