This article is the culmination of many months’ struggle, on and off, with using a somewhat complex object/class I wrote to store user settings into VB.Net’s My.Settings permanent storage provider. The information required to do so is out there, but it’s fragmented and often contradictory, and some articles/forum posts contain inaccuracies; so I set out to gather all the required information in one place, to save others the headaches I encountered.
Part One will cover the requirements for the class you create; Part Two will cover getting your object into My.Settings.
My.Settings is a Windows Forms feature in VB.Net that allows the programmer to store user-specific settings, such as the last location of the application’s window on the screen, user application preferences, etc., into permanent storage on the user’s hard drive, in a quick and easy manner.
There are application-specific settings, which are the same for all users on a given PC, and user settings, which are different for each user. We will be looking only at the latter here.
You can actually bind form and control settings, such as last form location or the form’s title bar text, to My.Settings directly in Visual Studio’s WinForms designer. What we’re going to look at here is a bit more complex.
Where is the data actually stored on the user’s hard drive?
The actual file containing the saved settings is named user.config; it is an XML file, and its location depends on your version of Windows: generally,
- Under Windows Vista (and, I would think, Windows 7, though I haven’t tested it):
C:\Users<user id>AppDataLocalApplication Data<companyname><appdomainname>[etc.]
- Under Windows XP:
C:\Documents and Settings><username>[Local Settings]Application Data<companyname><appdomainname>[etc.]
<companyname> is the name of the Company you entered in the Project settings; <appdomainname> may or may not appear.
The [etc.] in the above paths may include a build-specific hash etc. depending on whether you have strong-named the assembly; and there will be an additional directory for the version number of the build, again controlled by the setting in the applications Properties.
For an application I was writing, I needed to save approximately a dozen user-specified options of various datatypes into permanent storage. These were to be available to the user for editing in a fairly standard options dialog.
Having some positive experience using My.Settings for simple datatypes, as well as some experience using Binary Serialization for similar purposes, I decided to investigate whether I could use My.Settings for my needs.
It was simple enough to create several individual settings of various datatypes in the Settings editor in the Properties for my application, and manually load them into each control at app startup. However, as the number and complexity of settings began to increase, I decided that I wanted a single location for the settings that was not hidden away in a Visual Studio editor. I also wanted to take advantage of the drag-and-drop databinding available in VS 2005 (which was the current version when I first started the project). The answer seemed obvious—the documentation claimed that custom objects were supported. I was to learn that that support was fairly weak and severely under-documented; but it is possible to use even a pretty complex, nested class with My.Settings. It just takes a lot of detective work, and a bit of sweat!
Requirements for your class
You must meet the below requirements for the class you create, or it simply will not work with My.Settings, no matter what you try. I went down many dead ends, trying a dozen different unnecessary approaches, simply because I did not pay strict enough attention to the following simple rules.
The basic requirements for a class that will be used to hold settings in My.Settings are largely the same as for any XML-serializable:
- Your class must be decorated with the <Serializable()> attribute
- Your class must have a Public default constructor (New() sub) that takes no parameters
- Read-Only, Write Only, or Private Properties and/or Properties lacking Getters and Setters will not be saved to My.Settings
- Any Property in your class of a type from the .Net framework must be labeled as Serializable in the documentation
- Any other class contained in your class must adhere to the above requirements as well
The last item is particularly important; it tripped me up for several days before I realized that a class contained within my main settings class had two Read Only properties, and it was this fact that was causing the properties within that class to not be saved to disk.
Beyond the above, there are not many restrictions. My main settings class contains a Generic List of objects which are themselves a separate class, and you can generally include any datatype that can be represented as XML. My class contains a Hotkey combo class, which in turn includes System.Windows.Forms.Keys.
If you run into problems with datatypes beyond the basic string, integer, etc., you may need to implement the ISerializable interface within your class, and specify how the XML serialization should occur.
If so, make sure you have implemented the GetObjectData() and SetObjectData() ISerializable methods, and have .AddValue() and .GetValue() statements which map to all of your properties. You’ll also want the additional constructor with the signature:
Protected Sub New(ByVal info As SerializationInfo, ByVal context As StreamingContext)
Most of the above should be created for you in skeletal form once you hit the <Enter> key after typing in Implements ISerializable, though you will need to fill in the lines for each of your Properties. There are many examples in MSDN and on the Web.
I did not find this approach necessary, and I had several contained classes in my settings class, which included a few non-basic datatypes. I mainly include this for completeness.
Next, at least in VS 2008, make liberal use of the poorly-named “Synchronize” button in the Settings tab of your project’s Properties editor:
despite the misleading name, clicking this button will erase all saved My.Settings/settings files, returning your project to a known state with no saved data. This makes it much simpler to determine whether the settings data you are looking at are current or not. Your mileage may vary in VS 2005, as I have heard reports of problems with this tool in VS 2005.
Finally, I will add this: tackle any problems by temporarily simplifying your object: comment out everything other than a simple string Property, and get that working. Add the others back one by one until everything is working.