By Googling "winforms settings" (or some other similar query) you'll quickly find out that there's a built-in way to do this that is pretty simple. Once you set up a setting, you can simply call it throughout your project by using Properties.Settings.Default.[SettingName] .
Now here are the reasons why I'm proposing something different:
- Sometimes you need to be able to change the settings by modifying the settings file itself (rather than through the program's UI). This could be because a certain setting is causing the program to crash before it opens, it will lead to unwanted behavior upon launch, etc
- By creating your own, custom settings file you can choose where it will be saved. This leads to a great deal of flexibility, but also allows you to jump into creating a folder for your program in the user's AppData folder (where you can start putting other things like log files, credentials, temporary files, etc)
- A custom settings file leads to easier sharing of settings between two different computers (if you want to make sure two computers have the same settings)
- Creating a new setting is slightly faster with my implementation
To implement mine, you can simply add a new .cs file to your project like this (Remember: change "namespace TestProject" to your appropriate project's namespace):
So there's a few things to cover here. We'll go through this chunk by chunk.
First you'll notice lines 14-16 that define where our settings file is going to be saved. You can condense these into one line if you like or even change it up altogether. But this is the route I like to take (obviously change "Your Application" to fit the name that you are going to use for your application folder).
Next we have lines 19-22 that define our settings. This is where you'll make the majority of your changes. The great part about this is in order to add a setting, you just have to create another variable for it here (and initialize it with a default value). As examples, I have a bool, string, and double setting. Yes, it is necessary to keep the "Instance" variable - we'll get to that in a second.
Finally, we have the rest of the file: the SaveSettings() and ReadSettings() methods (you can rename these if you like). The purpose of these is to save your settings to a file or to read the settings from a file. Ideally, one of the first things your program does would be to call the ReadSettings method and get the user's settings. And every time a setting gets changed (and you also want that change reflected in the file) you'll call SaveSettings. Pretty simple to use!
The great thing about this method is that it uses the XmlSerializer class. XmlSerializer is great because it is type-independent. Meaning that the resulting Settings.xml for our file here will look like this:
That's it! All of it! You may notice that nowhere does the xml state that "Test" is a bool or "AnotherSetting" is a string. The values are simply stored plainly and the type cast happens when ReadSettings is called. Speaking of which, here are examples of how you would use this:
Notice that you have to use "Instance" when reading/writing a particular setting's value. This "Instance" is required for the XmlSerializer to work. (You could just call Settings.Test for example, but you would only get the default value - if you try to write to Settings.Test it won't get saved to the xml).
As a final note, notice the try{} catch{} in the ReadSettings method. This is in case one of the settings in the xml gets set to the wrong type (e.g. <ADouble>hi</ADouble>). This isn't a problem in the xml, but throws an exception when the XmlSerializer tries to type cast it back to a double. You can put some sort of log call, Console.WriteLine, etc in the catch{} and even add a finally{} with some different settings set. But as the code stands right now, it will simply fail to overwrite the Instance and instead the Instance will be set to its default value (which is a newly-initialized version of this class, containing the default values for all settings).
Hope this helps you out! Please let me know if you have any questions
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | using System; using System.IO; using System.Xml.Serialization; namespace TestProject { public class Settings { private static string applicationName = "Your Application"; private static string userSettings = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), applicationName); private static string serializationPath = Path.Combine(UserSettings, "Settings.xml"); #region Intialize settings with default values public bool Test = false; public string AnotherSetting = "this setting"; public double ADouble = 5.3; public static Settings Instance = new Settings(); #endregion Intialize settings with default values public static void SaveSettings() { TextWriter writer = new StreamWriter(serializationPath); XmlSerializer xmlSerializer = new XmlSerializer(typeof(Settings)); xmlSerializer.Serialize(writer, Instance); writer.Close(); } public static void ReadSettings() { if (File.Exists(serializationPath)) { FileStream fileStream = new FileStream(serializationPath, FileMode.Open); XmlSerializer xmlSerializer = new XmlSerializer(typeof(Settings)); try { Instance = (Settings)xmlSerializer.Deserialize(fileStream); } catch { } } } } } |
So there's a few things to cover here. We'll go through this chunk by chunk.
First you'll notice lines 14-16 that define where our settings file is going to be saved. You can condense these into one line if you like or even change it up altogether. But this is the route I like to take (obviously change "Your Application" to fit the name that you are going to use for your application folder).
Next we have lines 19-22 that define our settings. This is where you'll make the majority of your changes. The great part about this is in order to add a setting, you just have to create another variable for it here (and initialize it with a default value). As examples, I have a bool, string, and double setting. Yes, it is necessary to keep the "Instance" variable - we'll get to that in a second.
Finally, we have the rest of the file: the SaveSettings() and ReadSettings() methods (you can rename these if you like). The purpose of these is to save your settings to a file or to read the settings from a file. Ideally, one of the first things your program does would be to call the ReadSettings method and get the user's settings. And every time a setting gets changed (and you also want that change reflected in the file) you'll call SaveSettings. Pretty simple to use!
The great thing about this method is that it uses the XmlSerializer class. XmlSerializer is great because it is type-independent. Meaning that the resulting Settings.xml for our file here will look like this:
1 2 3 4 5 6 | <?xml version="1.0" encoding="utf-8"?> <Settings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <Test>false</Test> <AnotherSetting>this setting</AnotherSetting> <ADouble>5.3</ADouble> </Settings> |
That's it! All of it! You may notice that nowhere does the xml state that "Test" is a bool or "AnotherSetting" is a string. The values are simply stored plainly and the type cast happens when ReadSettings is called. Speaking of which, here are examples of how you would use this:
1 2 3 4 5 | Settings.ReadSettings(); //Read the settings from xml file Settings.Instance.Test = true; //Set "Test" to true Settings.Instance.AnotherSetting = "hi"; //Set "AnotherSetting to "hi" Settings.Instance.ADouble *= 5; //Set "ADouble" to 5x its current value Settings.SaveSettings(); //Save the settings to xml file |
Notice that you have to use "Instance" when reading/writing a particular setting's value. This "Instance" is required for the XmlSerializer to work. (You could just call Settings.Test for example, but you would only get the default value - if you try to write to Settings.Test it won't get saved to the xml).
As a final note, notice the try{} catch{} in the ReadSettings method. This is in case one of the settings in the xml gets set to the wrong type (e.g. <ADouble>hi</ADouble>). This isn't a problem in the xml, but throws an exception when the XmlSerializer tries to type cast it back to a double. You can put some sort of log call, Console.WriteLine, etc in the catch{} and even add a finally{} with some different settings set. But as the code stands right now, it will simply fail to overwrite the Instance and instead the Instance will be set to its default value (which is a newly-initialized version of this class, containing the default values for all settings).
Hope this helps you out! Please let me know if you have any questions