Click here to Skip to main content
Click here to Skip to main content
Go to top

Windows Forms - Creating and Loading Main Window Form and Child Control States Using VB.NET

, 9 Dec 2008
Rate this:
Please Sign up or sign in to vote.
This article provides a simple example of how to save your application's main form and some of the related child control settings programmatically by subclassing an instance of the ApplicationSettingsBase class found in the .NET System.Configuration namespace.

Sample Application ScreenShot

Introduction

When developing a Windows based application, we strive to provide a high level of usability. One of the simplest and most effective ways to ensure a high level of usability in a .NET Windows Forms based application is to save the main window size and position, along with the state of its related child controls. By saving the state of the main form and any related child controls, the user can pick up and resume using the application where they left off, the next time they need to run the same application.

This article provides an example of how to save your application's main form and some of the related child control settings programmatically by subclassing an instance of the ApplicationSettingsBase class found in the .NET System.Configuration namespace. To illustrate how you can develop and integrate your own subclass of the ApplicationSettingsBase class, I've provided a simple Windows Forms based application, SimplePersistentFormVBNET, that allows you to type in any text string and modify the font and word wrap settings within the main form's TextBox. As the application loads and runs, it attempts to set the main form to the same settings as last used in the previous session for running the application.

The sample application's ApplicationSettingsBase subclass, MainFormSettings, will save or persist the following settings each time the user exits the application:

  • The Location or position of the main form inside the main desktop window. If the previous session's location for the main application window is not available, the MainFormSettings class will automatically center the form when loaded.
  • The Size, or width and height of the main application Window.
  • The Font, its point size, and style when displaying or modifying text inside the main form's TextBox.

Background

ApplicationSettingsBase saves the main form and other application settings that you define as read-write properties in your application's own subclass in an XML based file named user.config. By default, the user.config is saved on a per Windows user basis in an application specific subdirectory under the Local Settings\Application Data directory path referenced in the USERPROFILE Windows environment variable. To determine the actual application settings specific subdirectory that will contain the user.config file, the .NET Framework's backing implementation of the ApplicationSettingsBase class will check the following set of properties defined in your application's assembly at runtime:

Using the Code

MainFormSettings.vb

MainFormSettings is the subclass of ApplicationSettingsBase that contains the four main application window settings that we'll save between runs: the Location and Size of the form, the Font for displaying text within the Windows.Forms.TextBox control, and WordWrap, a boolean value indicating if each line in the TextBox will be automatically wrapped.

Option Explicit On
Option Strict On

Imports System
Imports System.Configuration
Imports System.Diagnostics
Imports System.Drawing
Imports System.Windows.Forms

Public Class MainFormSettings
    Inherits ApplicationSettingsBase

    Private ReadOnly DefaultWidth As Int32 = 480
    Private ReadOnly DefaultHeight As Int32 = 360

    <UserScopedSetting()> _
    Public Property Location() As Point
        Get
            If IsNothing(Me.Item("Location")) Then
                Dim mainFormSize As Size = Me.Size

                Dim startingXPos = _
                  Convert.ToInt32((Screen.PrimaryScreen.Bounds.Width \ 2) - _
                                  (mainFormSize.Width \ 2))

                Dim startingYPos = _
                  Convert.ToInt32((Screen.PrimaryScreen.Bounds.Height \ 2) - _
                                  (mainFormSize.Height \ 2))

                Me.Item("Location") = New Point(startingXPos, startingYPos)

                Return CType(Me.Item("Location"), Point)
            Else
                Return CType(Me.Item("Location"), Point)
            End If
        End Get

        Set(ByVal value As Point)
            Me.Item("Location") = CType(value, Point)
        End Set
    End Property

    <UserScopedSetting()> _
    Public Property Size() As Size
        Get
            If IsNothing(Me.Item("Size")) Then
                Me.Item("Size") = New Size(DefaultWidth, DefaultHeight)
                Return CType(Me.Item("Size"), Size)
            Else
                Return CType(Me.Item("Size"), Size)
            End If
        End Get

        Set(ByVal value As Size)
            Me.Item("Size") = CType(value, Size)
        End Set
    End Property

    <UserScopedSetting()> _
    Public Property Font() As Font
        Get
            If IsNothing(Me.Item("Font")) Then
                Me.Item("Font") = New Font("Courier New", 11, _
                                            FontStyle.Regular)
                Return CType(Me.Item("Font"), Font)
            Else
                Return CType(Me.Item("Font"), Font)
            End If
        End Get

        Set(ByVal value As Font)
            Me.Item("Font") = CType(value, Font)
        End Set
    End Property

    <UserScopedSetting(), DefaultSettingValue("False")> _
    Public Property WordWrapEnabled() As Boolean
        Get
            Return CType(Me.Item("WordWrapEnabled"), Boolean)
        End Get

        Set(ByVal value As Boolean)
            Me.Item("WordWrapEnabled") = CType(value, Boolean)
        End Set
    End Property

End Class
MainFormSettings.vb - An ApplicationsSettingsBase subclass.

Each of the four properties saved between user sessions of running the application are declared as instances of the UserScopedSetting attribute class, which will be added to the <userSettings> section of the user.config XML file. Along with the UserScopedSetting attribute, we can also specify a default value for a property that will be used if the user.config file cannot be accessed or doesn't exist, as in running the application for the first time. Default user setting values are defined using the DefaultSettingValueAttribute class. For example, with the MainFormSettings.WordWrapEnabled property, word wrapping in the application's MainEditTextBox control is disabled by default:

<UserScopedSetting(), DefaultSettingValue("False")> _
Public Property WordWrapEnabled() As Boolean
    Get
        Return CType(Me.Item("WordWrapEnabled"), Boolean)
    End Get

    Set(ByVal value As Boolean)
        Me.Item("WordWrapEnabled") = CType(value, Boolean)
    End Set
End Property
The MainFormSettings.WordWrapEnabled property - By default, word wrapping in the sample application is disabled.

The ApplicationSettingsBase class serializes the WordWrapEnabled property as a string, and adds the property in its own XML <setting> element in the <userSettings> section of the user.config file:

<userSettings>
    <SimplePersistentFormVBNET.MainFormSettings>
       <!-- Additional Size & Location properties omitted here for clarity. -->
        <setting name="WordWrapEnabled" serializeAs="String">
            <value>True</value>
        </setting>
        <!-- Additional Font property omitted here for clarity. -->
    </SimplePersistentFormVBNET.MainFormSettings>
</userSettings>
The MainFormSettings.WordWrapEnabled property as it is formatted and saved in the XML based user.config file.

Of the four application properties defined in the MainFormSettings class, two additional properties have default values defined in a similar manner: Size and Font. Like the WordWrap property, the System.Drawing instance values for both Size and Font are serialized and added to the user.config XML file as strings.

Location Property and Centering the Main Application Form by Default

Since the screen resolution and the number of monitors the PC may have configured for running applications can differ from system to system, the Location property in the MainFormSettings class does not provide a default System.Drawing.Point value. Instead, the Location property Get accessor checks for a null reference to a Point value structure. If the Point is a null reference, as it will be the first time you run the sample application on a PC that doesn't have a user.config file for the current Windows user, the Get method section will determine the vertical and horizontal center of the primary display at which to open the application's main form based on its Size property.

<UserScopedSetting()> _
Public Property Location() As Point
    Get
        If IsNothing(Me.Item("Location")) Then
            Dim mainFormSize As Size = Me.Size

            Dim startingXPos = _
            Convert.ToInt32((Screen.PrimaryScreen.Bounds.Width \ 2) - _
                            (mainFormSize.Width \ 2))

            Dim startingYPos = _
            Convert.ToInt32((Screen.PrimaryScreen.Bounds.Height \ 2) - _
                            (mainFormSize.Height \ 2))

            Me.Item("Location") = New Point(startingXPos, startingYPos)

            Return CType(Me.Item("Location"), Point)
        Else
            Return CType(Me.Item("Location"), Point)
        End If
    End Get

    Set(ByVal value As Point)
        Me.Item("Location") = CType(value, Point)
    End Set
End Property
Initializing the default main form Location property to center the form in the primary display based on its default size.

In order to determine the center of the main application form from within the Location property accessor, we must know what the current or default size of the form is. We can access the Size property value, either the default or the current Size, by using the Me reference to our same instance of the MainFormSettings class, as in:

If IsNothing(Me.Item("Location")) Then
    ' Accessing the default Size property value within the same
    ' MainFormSettings class...
    Dim mainFormSize As Size = Me.Size

In order to ensure that the MainForm class will load and position itself at the correct startup location, the Windows.Forms.Form StartPosition property must be changed from its default value of WindowsDefaultLocation to Manual. This will allow us to load and use the MainFormsSetting.Location property to automatically center the main application window for the first time, or restore it to its last position from a previous user session.

MainForm StartPosition In IDE

Modifying the MainForm.StartPosition property using the Visual Studio Designer to allow the application code to set its starting position programmatically.

Accessing MainFormSettings from Within the Application

Loading the Settings

The main application window for the sample application, MainForm, contains a single private data member, _theSettings, which is an instance of the ApplicationSettingsBase subclass, MainFormSettings. The MainFormSettings class can be instantiated in either the MainForm constructor or in the MainForm Load event handler, or in any other member function, as long as it's instantiated before it's used. For simplicity and to keep the sample code concise, I've added the instantiation of the MainFormSettings class in the MainForm Load event handler, MainForm_Load().

Private Sub MainForm_Load(ByVal sender As System.Object, _
            ByVal e As System.EventArgs) Handles MyBase.Load
    _theSettings = New MainFormSettings()

    Me.Size = _theSettings.Size
    Me.Location = _theSettings.Location

    MainEditTextBox.Font = _theSettings.Font
    MainEditTextBox.WordWrap = _theSettings.WordWrapEnabled

    Return
End Sub
The MainForm Load event handler: Instantiating and setting the application settings when the main application window is displayed for the first time.

If we don't check the current MainForm WindowState property to see if the main application window is minimized, the user would only be able to view the MainForm in its maximized state. Additionally, the Restore application window context menu item would only minimize the MainForm again and keep the form in its minimized state.

Regardless as to whether or not the MainForm is minimized, we can always safely save the MainEditTextBox's selected Font and WordWrap properties to our ApplicationSettingsBase subclassed object, _theSettings, and have the same basic display and layout of any text that is typed or pasted into the TextBox control as found when the application was last run.

Additional Note

This sample application works without any issues on dual screen system configurations, including when opening a previous session with the form's Location and Size properties as saved in the user.config file, as well as setting the initial position of the MainForm to the secondary display monitor.

Additional Resources

  • MSDN Online: Windows Forms Programming - Application Settings For Windows Forms
  • The basis for this article on how I could initialize, save, and restore an application’s state is in the article How to: Create Application Settings, which can be found at MSDN. If you are working in .NET 3.0 or .NET 2.0, with Visual Studio 2005, you may want to review the quick links provided by MSDN for your specific development platform.

  • Windows Forms 2.0 Programming Sells, Chris Sells, Weinhardt, Michael (2006: Addison-Wesley, ISBN-10 0321267966, ISBN-13 9780321267962, 988 pages)
  • This book is perhaps one of the few .NET development books I would consider as "a must have" on your bookshelf. Of special interest in working with the .NET Framework support for persisting application and user settings can be found in Chapter 15, entitled Settings. The Settings chapter provides the most extensive overview and information on working with Application Settings, User Settings, and Roaming-User Settings, in addition to working with the Settings Designer tools inside Visual Studio. Unfortunately, neither Chris Sells nor Justin Ghetland have followed up to their 2003 publication, Windows Forms Programming in Visual Basic .NET, which covers the initial release of the Windows Forms classes in .NET 1.0 and 1.1, and as a result, will not have any information comparable to what is found on the System.Configuration sections in Windows Forms Programming 2.0. Nonetheless, if coming from an essentially Visual Basic background, spending the extra time and effort to work through the C# version is well worth it.

  • The Code Project Windows Forms - Creating and Persisting Custom User Settings in C# Gennaro, Frank (2487219)
  • In this article, Frank provides a great overview on how you can easily support serialization of custom objects to an ApplicationSettingsBase subclass, beginning with the Windows Forms Project Properties Settings Designer, and then follows through with a quick sample on how to save and load a System.Collections.Generic.SortedList containing a custom object. If my article was of value to you as to how you can improve your application's overall level of usability, then Frank's article should be the next article on your reading list. If you're not as comfortable in reading and working with C# syntax, you can always look at the compiled sample application, CustomUserSettings.exe using Red Gate's .NET Reflector and disassemble the .EXE in Visual Basic .NET.

History

  • 08-Dec-08: Original article submitted.

License

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

Share

About the Author

ClockEndGooner
Software Developer
United States United States
No Biography provided

Comments and Discussions

 
GeneralApplicationScopedSetting Pinmemberbarts00722-Jan-10 7:16 

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

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

| Advertise | Privacy | Mobile
Web01 | 2.8.140916.1 | Last Updated 9 Dec 2008
Article Copyright 2008 by ClockEndGooner
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid