Introduction
The class saves the state (location, size and windows state) of a form to registry (under HKEY_CURRENT_USER) when the form is closed and restores the form state when it is loaded. (To work with .NET 1.x one need to use some other events and a couple of methods are new to .NET 2.0).
It will also work with multi screen desktops. The key here is to use Form.DesktopBounds
and not Form.Location
and Form.Size
. Also i case of screens not always being there I use Screen.GetBounds()
to check and if needed move form to an existing screen.
To use just include the following line in the constructor of your Form:
FormState formState = new FormState(this, "SampleApp");
Also got some methods for storing and getting other settings regarding the form in registry (SaveValue()
, GetValue()
, GetIntValue()
). Use these in the FormClosed and Load event handlers store and restore whatever... (need to keep the FormState object as a variable of your form class in this case).
The class:
using System;
using System.Drawing;
using Microsoft.Win32;
using System.Windows.Forms;
class FormState
{
private Form _parent;
private string _registry_key;
public FormState(Form parent, string subkey)
{
this._parent = parent;
this._registry_key = subkey + "\\FormState";
this._parent.Load += new EventHandler(On_Load);
this._parent.FormClosed += new FormClosedEventHandler(On_FormClosed);
}
public void SaveValue(string name, object value)
{
this.RegKey.SetValue(name, value);
}
public object GetValue(string name, object default_value)
{
return this.RegKey.GetValue(name, default_value);
}
public int GetIntValue(string name, int default_value)
{
int val = default_value;
if (!int.TryParse(this.RegKey.GetValue(name, default_value).ToString(), out val))
val = default_value;
return val;
}
private RegistryKey RegKey
{
get
{
return Registry.CurrentUser.CreateSubKey(
this._registry_key + "\\" + this._parent.Name);
}
}
private void On_Load(object sender, EventArgs e)
{
int X, Y, width, height, window_state;
RegistryKey key = this.RegKey;
if (!int.TryParse(key.GetValue("DesktopBounds.Width",
this._parent.DesktopBounds.Width).ToString(),
out width))
width = this._parent.DesktopBounds.Width;
if (!int.TryParse(key.GetValue("DesktopBounds.Height",
this._parent.DesktopBounds.Height).ToString(),
out height))
height = this._parent.DesktopBounds.Height;
if (!int.TryParse(key.GetValue("DesktopBounds.X",
this._parent.DesktopBounds.X).ToString(),
out X))
X = this._parent.DesktopBounds.X;
if (!int.TryParse(key.GetValue("DesktopBounds.Y",
this._parent.DesktopBounds.Y).ToString(),
out Y))
Y = this._parent.DesktopBounds.Y;
Rectangle screen_bounds = Screen.GetBounds(new Point(X, Y));
if (X > screen_bounds.X + screen_bounds.Width)
{
X = screen_bounds.X;
Y = screen_bounds.Y;
}
this._parent.DesktopBounds = new Rectangle(X, Y, width, height);
if (!int.TryParse(key.GetValue("WindowState",
(int)this._parent.WindowState).ToString(),
out window_state))
window_state = (int)this._parent.WindowState;
this._parent.WindowState = (FormWindowState)window_state;
}
private void On_FormClosed(object sender, FormClosedEventArgs e)
{
this._parent.FormClosed -= new FormClosedEventHandler(On_FormClosed);
RegistryKey key = this.RegKey;
key.SetValue("WindowState", (int)this._parent.WindowState);
if (this._parent.WindowState != FormWindowState.Normal)
this._parent.WindowState = FormWindowState.Normal;
key.SetValue("DesktopBounds.Y", this._parent.DesktopBounds.Y);
key.SetValue("DesktopBounds.X", this._parent.DesktopBounds.X);
key.SetValue("DesktopBounds.Width", this._parent.DesktopBounds.Width);
key.SetValue("DesktopBounds.Height", this._parent.DesktopBounds.Height);
}
}
A note on the FormClosed
event. When the main form (used in Application.Run()
) is closed, the application quits and all forms created after the main form was created are also closed. One would think that the FormClosing
and FormClosed
event would be raised for all forms. This does not seem to be the case.
I solve this by using the following in the main form:
private void On_FormClosing(object sender, FormClosingEventArgs e)
{
this.FormClosing -= new FormClosingEventHandler(On_FormClosing);
Application.Exit(e);
}
private void On_FormClosed(object sender, FormClosedEventArgs e)
{
this.FormClosed -= new FormClosedEventHandler(On_FormClosed);
}
in the
FormClosing
event for the main form of the application. This raises the
FormClosing
and
FormClosed
event for all open forms.
Passing the FormClosingEventArgs
param to Application.Exit()
gives the other forms a chance to cancel quitting the application.
Removing the FormClosing
and FormClosed
delegates prevents the methods from being called a second time (as Application.Exit()
will raise the events for the main form as well as the others).
This class was created after having used various laboursome methods over the years and finally getting tired of it.
Various articles and blogs on the internet including an article ("Saving and Restoring the Location, Size and Windows State of a .NET Form") by Joel Matthias here on the Code Project was the inspiration for this class.
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.