Retaining a single set of user settings for your application is easy.

Retaining multiple sets of user settings is much more challenging.

Many Windows applications allow the user to define preferences that customize the application’s appearance and behavior. One of the most common examples of user customizations is the ability to move and resize a form. The user can move or resize a form and then exit the application. When the user opens the application again, the form is restored to the last user-defined position and size.

The SettingsKey is the key feature that allows you to have multiple sets of settings.

The new settings feature in Visual Studio 2005 provides a very easy way to store these user preferences upon exit of the application and restore them when the user opens the application again. But these simple techniques only support one set of named settings. So if you have 20 forms in your application, do you need 20 named settings for the form location and 20 named settings for the form size? Luckily, the answer is no. With a little more work you can retain multiple sets of user settings.

This article first reviews the fundamentals of user settings. It then details how to work with multiple sets of user settings.

User Settings Fundamentals

A common user request is for your application to remember its state so that the application can be returned to that state when the user runs the application again. For example, if the user laid out the windows of the application in a specific manner and then closed the windows, the user expects that the windows will be returned to their last defined locations and sizes when they are reopened.

Visual Studio 2005 added a Settings tab on the Project Designer window to support the management of application settings. Application settings allow you to store and retrieve property settings and other information for your application. You can use application settings to maintain custom application settings and end-user preferences.

You can use this feature for application settings that you don’t want hard-coded into the application, such as your connection string. You can also use this feature to store end-user preferences such as form size and location and color choices. In either case, application settings are available within the code of your application using the My.Settings object.

To define an application setting:

The result is shown in Figure 1.

Figure 1:  The Settings tab of the Project Designer allows you to define user preference and application settings.
Figure 1: The Settings tab of the Project Designer allows you to define user preference and application settings.

There are some application settings, such as form location, that can be bound directly to a property of a form or control at design time. For Visual Basic applications, the runtime automatically stores the setting before the form is closed and automatically restores the setting when the form is opened again.

To bind a setting to a property of a form or control at design time:

Figure 2:  The ApplicationSettings properties allow you to bind a setting to a specific form or control property.
Figure 2: The ApplicationSettings properties allow you to bind a setting to a specific form or control property.

Notice in Figure 2 that there are only two form properties that can be bound to user settings at design time. All other user settings must be set and restored in the code. The form size cannot be bound directly to a property because it requires additional code to handle the maximized and minimized case.

For form-specific user preferences, you can set the value of the setting before the form is closed. For the form size example, set the FormSize setting before closing the form as follows:

Private Sub CustomerWin_FormClosing(ByVal sender _
   As Object, ByVal e _
   As System.Windows.Forms.FormClosingEventArgs) _
   Handles Me.FormClosing
  If Me.WindowState = FormWindowState.Normal Then
    My.Settings.FormSize = Me.Size
  Else
    ' If the form was maximized or minimized,
    ' return to the restore state
    My.Settings.FormSize = Me.RestoreBounds.Size
  End If
End Sub

This code first checks the form state. If the WindowState is normal, you can simply store the form size. But if the WindowState is any other state, such as minimized or maximized, you must use the RestoreBounds size. Additionally, you could define a setting for WindowState so you can return the form to its original state.

You restore the user setting when the form is opened:

Private Sub CustomerWin_Load(ByVal sender As _
   Object, ByVal e As System.EventArgs) _
   Handles Me.Load
  If My.Settings.FormSize <> _
           System.Drawing.Size.Empty Then
    Me.Size = My.Settings.FormSize
  End If
End Sub

The settings are stored in two XML files: an app.config file, which is created at design time when you create the first application setting; and a user.config file, which is created at runtime when the user changes the value of any user setting.

The user.config file is stored in:

C:\Documents and Settings\<your username>\
Local Settings\Application Data

This is called the local user profile. Alternatively, it will be stored in:

C:\Documents and Settings\
<your username>\Application Data

This is called the roaming user profile.

Note: If you use ClickOnce deployment, the settings will be saved in the ClickOnce data directory and not in the local user configuration file.

The Visual Basic runtime automatically saves the user.config settings when the application is closed and retrieves the settings when the application is opened again.

The userSettings section of the user.config XML file for the two settings defined here looks like this:

<userSettings>
    <PTWin.My.MySettings>
        <setting name="FormLocation"
                           serializeAs="String">
            <value>57, 11</value>
        </setting>
        <setting name="FormSize" 
                           serializeAs="String">
            <value>566, 362</value>
        </setting>
    </PTWin.My.MySettings>
</userSettings>

Use these new settings features whenever you have application properties that you don’t want to hard-code into the application and when you want to store and retrieve a single set of user preferences.

Retaining Multiple Sets of User Settings

As currently defined, the FormLocation and FormSize example settings will only work for one form. For a consistent user interface, you would want the settings retained for each of the forms in your application.

One way to define settings for each of your forms is to define a unique set of settings for each form. You could then use the techniques defined above. But that would be a significant amount of work, especially if your application has a large number of forms.

A better approach is to create your own MySettings object and use the SettingsKey property to define a key for each form. To minimize the amount of repeated code required for this, add the code to a base form class as defined in my article, “Give Your Forms a Base” (CoDe Magazine March/April 2004).

To define multiple sets of settings, begin by creating your own MySettings object. Insert a property into your base form class that will create and retain your specialized MySettings object:

Private _settings As My.MySettings
Private ReadOnly Property Settings() As _
    System.Configuration.ApplicationSettingsBase
  Get
    If _settings Is Nothing Then
      _settings = New My.MySettings
    End If
    Return _settings
  End Get
End Property

This code declares a private member variable to retain your custom MySettings object. It defines a private read-only property that will initially create an instance of your custom setting. It then returns the custom setting for use within the base form class.

Next you’ll create a method in your base form class to apply the settings from your custom MySettings object. This method will be called when the form is loaded to apply the settings to your form, basically resetting the form size and location to the saved settings.

''' <summary>
''' Applies the settings for every form
'''       </summary>
Private Sub ApplySettings()
  Settings.SettingsKey = Me.Name
  Dim theSettings As My.MySettings
  theSettings = DirectCast(Settings, _
                               My.MySettings)
  If theSettings.FormSize <> Size.Empty Then
    Me.Size = theSettings.FormSize
  End If
  If theSettings.FormLocation <> Point.Empty Then
    Me.Location = theSettings.FormLocation
  End If
End Sub

The first line of this method sets the SettingsKey. The SettingsKey is the key feature that allows you to have multiple sets of settings. Each set of settings has a unique SettingsKey. In this case, it is assigned as the name of the form to associate the settings with the particular form.

The next two lines cast your Settings property to your MySettings object. This maps the appropriate settings to your Settings property so the SettingsKey must be set prior to performing this cast.

The casting is required because the property is of type System.Configuration.ApplicationSettingsBase. In order to access your specific properties, you need to cast it to your MySettings object.

Note: The MySettings class is generated by Visual Studio and can be found in the My Project subdirectory for the project in the Settings.Designer.vb file.

The remainder of this method is similar to the code defined earlier for applying the settings. When defining your own settings, you cannot bind the settings with properties in the Properties window. You instead need to manually set the properties.

You also need to create a method in your base form class to save the settings in your custom MySettings object. This method will be called when the form is closed to save the settings.

''' <summary>
''' Saves the settings for each form
'''       </summary>
Private Sub SaveSettings()
  Settings.SettingsKey = Me.Name
  Dim theSettings As My.MySettings
  theSettings = DirectCast(Settings, _
                              My.MySettings)

  If Me.WindowState = FormWindowState.Normal Then
    theSettings.FormSize = Me.Size
  Else
    ' If the form was maximized or minimized,
    ' return to the restore state
    theSettings.FormSize = Me.RestoreBounds.Size
  End If
  theSettings.FormLocation = Me.Location

  Settings.Save()
End Sub

The first line of this method sets the SettingsKey to the name of the form. This ensures that the settings are associated with the particular form. The next two lines cast your Settings property to your MySettings object. This maps the appropriate settings to your Settings property so the SettingsKey must be set prior to performing this cast.

The casting is required because the property is of type System.Configuration.ApplicationSettingsBase. In order to access your specific properties, you need to cast it to your MySettings object.

The next set of code sets the FormSize setting to the size of the form. The code to manually set the FormLocation setting is also defined because it was no longer set automatically using the Properties window. The last line of code saves your settings. The automatic saving of settings described earlier does not save your custom settings.

The last step is to modify the form Load and FormClosing events in the base form class to call these two methods.

The form Load event handler is as follows:

Private Sub PTBaseWin_Load(ByVal sender _
    As Object, ByVal e As System.EventArgs) _
    Handles Me.Load
  ' Ensure the form is restored appropriately as
  ' per the settings
  ApplySettings()
End Sub

The form FormClosing event handler is:

Private Sub PTBaseWin_FormClosing(ByVal sender _
    As Object, ByVal e As _
    System.Windows.Forms.FormClosingEventArgs) _
    Handles Me.FormClosing
  ' Save the form's settings
  SaveSettings()
End Sub

To try this out, add the Settings property and ApplySettings and SaveSettings method to a base form class (or directly into one of your forms). Then call the two methods in the form Load and FormClosing events. Run the application and display one of your forms (a form that inherits from the base form class, if you added the code to a base form class; otherwise the form containing the settings code). Size and move the form then close the application. If all is well, when you reopen the application the form should resize and reposition itself.

If you had a ProductWin form and CustomerWin form that used this settings code, the resulting user.config file will look similar to this:

<userSettings>
    <PTWin.My.MySettings.ProductWin>
        <setting name="FormLocation" 
                           serializeAs="String">
            <value>189, 2</value>
        </setting>
        <setting name="FormSize"
                           serializeAs="String">
            <value>434, 359</value>
        </setting>
    </PTWin.My.MySettings.ProductWin>
    <PTWin.My.MySettings.CustomerWin>
        <setting name="FormLocation" 
                           serializeAs="String">
            <value>50, 140</value>
        </setting>
        <setting name="FormSize" 
                           serializeAs="String">
            <value>184, 190</value>
        </setting>
    </PTWin.My.MySettings.CustomerWin>
</userSettings>

Notice that there are now specialized PTWin.My.MySettings tags for ProductWin and CustomerWin. Any form that inherits from the base form class will get a section in this user.config file to define its settings.

Note: You can clear your user.config files at any time by clicking the Synchronize button on the Settings tab of the Project designer as shown in Figure 1. This deletes the user.config files. They will then be recreated the next time you run the application.

Conclusion

By creating your own settings object and using the SettingsKey, you can define multiple sets of settings. The code in this article used this feature to implement a set of settings for each form in the application, but you can use this same technique any time you want to assign multiple sets of settings.

As another example, a requirement of your application may be to allow the user to modify the parameters for any grid on any form. The user can define filter criteria, sort any column, and resize columns. You could use the SettingsKey to define a unique key for each grid. Then you can store and reapply settings for each grid.