Introduction
I wanted to create an easy way to setup a Settings (options) dialog box similar to the Options box of Visual Studio when you go to Tools > Options. There were a few requirements I wanted to include like, reusability, handling many data types, categories, sorting and spaces in the names. For complete explanation of the code described in this article, please download the source code and read the comments. Each function/subroutine is fully commented, as well as has the new XML comments (new for VB) for each one (no XML comments are on control handlers).
12/12/2005 - I'd like to thank Peter Spiegler for sending me the code to support system-defined enumerations.
The settings
The great part about this dialog box is that it reads all the settings from the My.Settings
namespace, which means you can create/edit your default settings directly from the IDE designer. You can do this by going to Project > {name} Properties... and then going to the Settings page.
There are a few rules that are imposed on your settings in order for them to show up in the dialog box:
- The name must have an underscore in it.
- The data type must be supported (see below for a list of supported data types).
- The setting must be UserScoped.
The underscore is required so that it can separate the actual name of your setting from the category you wish to put it in. See the screenshot below for some examples:
You'll notice several settings in the screenshot have double underscores in their names. This was to allow spaces in either the category name or in the setting name itself. You'll also notice that all the names in the screenshot have a number after them. This is for the settings sort index within its own category. The setting needs to have a scope of user, not application. When a setting has a scope of application - it is readonly at runtime, and since we want to change these settings at runtime it must have a scope of user.
There are several data types that are supported by the IDE's Settings Designer, but it is a little more difficult to support data types such as a TimeSpan, or a GUID. While a TextBox
could provide support for editing these, I didn't want to mess with the validation, and the use of these as User scoped objects that you'd want to change in an Options dialog, I felt, was rare. The list of supported types:
Byte
Char
Decimal
Double
Integer
Long
SByte
Short
Single
String
UInteger
ULong
UShort
- System-defined Enums (added on 12-12-2005)
Using this form
Using the form is like using any other form. Declare an instance of it and use the ShowDialog
method. There are several different styles to choose from - see below for more details on them.
Dim f As New frmOptions
f.Style = frmOptions.OptionsStyle.FireFox2
f.ShowDialog(Me)
The styles (12/12/2005)
There are four different styles that you can use. TreeView
and TabPages
aren't anything new, but since 12/12/2005 I've included support for FireFox1
and FireFox2
. FireFox1
is the style of the options box in FireFox before version 1.5 came out. FireFox2
is the style of FireFox version 1.5. Just changing that one line of code f.Style = frmOptions.OptionsStyle.FireFox2
you can change the look of the dialog box. Watch out when using the TreeView
style, as it can be confusing for non-technical users (which most likely make up a majority of your user base - thanks Anna). For the FireFox styles, you can also add images. Currently these images must be 32x32 for the controls width/height support, however feel free to modify the code to support other sizes. Here is an example from the downloadable source:
Dim f As New frmOptions
f.Style = frmOptions.OptionsStyle.FireFox2
f.ImageAdd("Database", My.Resources.database)
f.ImageAdd("Misc", My.Resources.ClockFace)
f.ImageAdd("Fonts", My.Resources.fonts)
f.ImageAdd("Colors", My.Resources.circles)
f.ImageAdd("COM", My.Resources.rotary_phone)
f.ShowDialog(Me)
ImageAdd
allows you to add the images. Here I have all my images loaded as resources so that I can easily reference them. You must specify the main group that each image ties to as you add them, or they will not show up.
TreeView
TabPages
FireFox1
FireFox2
The form
The form is relatively simple. I have a TreeView
anchored on the left with a TableLayoutPanel
anchored on the right. These serve as the housing for the settings. One note about the TreeView
- the path separator is a period. There is also a checkbox, so that the users can choose whether they want to save their settings when the application exits or not, as well as the standard "OK", "Cancel" and "Apply" dialog buttons.
Loading the settings
In order to be able to change the settings, but not apply them (hence the Apply and OK buttons) we need to have a storage spot for all our setting information. So, I created a class with a collection to store that information for us - SettingInfo
and SettingInfoCollection
. Each object of SettingInfo
needs to store the Name
, Category
, SortIndex
, and Value
. There is a subroutine in the class that will load all these, when called passing it the true setting name (what you see in the designer). The collection should return to us all the settings of a given category, and change a value (or even a full item for sorting) for a given Index or true name.
In the Load
event of the form, we need to load all the settings available to us. To do that we need to cycle through each SettingsProperty
in My.Settings.Properties
, adding each one to the collection:
chkSaveOnExit.Checked = My.Application.SaveMySettingsOnExit
Dim sp As System.Configuration.SettingsProperty = Nothing
For Each sp In My.Settings.Properties
If sp.Name.IndexOf("_") <> -1 AndAlso _
IsUserScope(sp) AndAlso IsAllowedType(sp) Then
Dim newSetting As New SettingInfo
newSetting.LoadData(sp.Name)
Settings.Add(newSetting)
End If
Next
quickSort(Settings)
LoadTreeView()
To load the categories into the TreeView
(see the LoadTreeView()
method), I have a function that adds the categories/sub-categories from an array.
Displaying the edit controls
After a category is selected from the TreeView
- which should happen when you first display the form - the controls need to be displayed. The TreeView
was an optimal control for displaying the categories because of the FullPath
property of the nodes. So, in order to get all the settings of the selected category we just use the function provided in the class:
Dim sets() As SettingInfo = _
Settings.GetByCategory(tvCategories.SelectedNode.FullPath)
From here, I cycle through all the settings returned to me, and determine the appropriate control to use for editing, adding handlers to each control's LostFocus
event to update the value stored in the collection.
Applying the settings
Applying the settings is very easy - just loop through each setting in the collection and update the value stored in the My.Settings
namespace:
For Each si As SettingInfo In Settings
My.Settings.Item(si.TrueName) = si.Value
Next
My.Application.SaveMySettingsOnExit = chkSaveOnExit.Checked
Hitting either the OK or Apply button will trigger the code given above. Apply will not close the dialog box. OK sets the DialogResult to OK and is the Accept button of the form. Cancel is the Cancel button of the form and will set DialogResult to CANCEL.
During runtime, if you've unchecked the save settings on the exit checkbox, the settings will apply correctly when you change them, but after you restart the application they will again be at their defaults. Leaving it checked will ensure that the settings you've changed are carried on to the next run of the program.
Conclusion
I really hate writing conclusions. I'll let you, the readers, come to your own conclusion about this code. I hope you find this helpful and easy to use.