
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, SimplePersistentFormCS
, 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 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 the 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.cs
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.
using System;
using System.Configuration;
using System.Diagnostics;
using System.Drawing;
using System.Windows.Forms;
namespace SimplePersistentFormCS
{
class MainFormSettings : ApplicationSettingsBase
{
[UserScopedSetting()]
public Point Location
{
get
{
if (this["Location"] == null)
{
Size mainFormSize = this.Size;
int startingXPos =
((int)(Screen.PrimaryScreen.Bounds.Width / 2)) -
((int)(mainFormSize.Width / 2));
int startingYPos =
((int)(Screen.PrimaryScreen.Bounds.Height / 2)) -
((int)(mainFormSize.Height / 2));
this["Location"] =
new Point(startingXPos, startingYPos);
return (Point)this["Location"];
}
else
{
return (Point) this["Location"];
}
}
set
{
this["Location"] = (Point)value;
}
}
[UserScopedSetting()]
[DefaultSettingValueAttribute("480, 360")]
public Size Size
{
get
{
return (Size)this["Size"];
}
set
{
this["Size"] = (Size)value;
}
}
[UserScopedSetting()]
[DefaultSettingValueAttribute("Courier New, 11pt")]
public Font Font
{
get
{
return (Font)this["Font"];
}
set
{
this["Font"] = (Font)value;
}
}
[UserScopedSetting()]
[DefaultSettingValueAttribute("false")]
public bool WordWrapEnabled
{
get
{
return (bool)this["WordWrapEnabled"];
}
set
{
this["WordWrapEnabled"] = (bool) value;
}
}
}
}
MainFormSettings.cs - 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. The 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()]
[DefaultSettingValueAttribute("false")]
public bool WordWrapEnabled
{
get
{
return (bool)this["WordWrapEnabled"];
}
set
{
this["WordWrapEnabled"] = (bool) value;
}
}
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>
<SimplePersistentFormCS.MainFormSettings>
-->
<setting name="WordWrapEnabled" serializeAs="String">
<value>True</value>
</setting>
-->
</SimplePersistentFormCS.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 Point Location
{
get
{
if (this["Location"] == null)
{
Size mainFormSize = this.Size;
int startingXPos =
((int)(Screen.PrimaryScreen.Bounds.Width / 2)) -
((int)(mainFormSize.Width / 2));
int startingYPos =
((int)(Screen.PrimaryScreen.Bounds.Height / 2)) -
((int)(mainFormSize.Height / 2));
this["Location"] =
new Point(startingXPos, startingYPos);
return (Point)this["Location"];
}
else
{
return (Point) this["Location"];
}
}
set
{
this["Location"] = (Point)value;
}
}
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 this
reference to our same instance of the MainFormSettings
class, as in:
if (this["Location"] == null)
{
Size mainFormSize = this.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.

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 void MainForm_Load(object sender, EventArgs e)
{
_theSettings = new MainFormSettings();
this.Size = _theSettings.Size;
this.Location = _theSettings.Location;
MainEditTextBox.Font = _theSettings.Font;
MainEditTextBox.WordWrap = _theSettings.WordWrapEnabled;
return;
}
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 here. 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.
- 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.
History
- 08-Dec-08: Original article submitted.