.NET WPF Remember window size between sessions

Save the values in the user.config file.

You'll need to create the value in the settings file - it should be in the Properties folder. Create five values:

  • Top of type double
  • Left of type double
  • Height of type double
  • Width of type double
  • Maximized of type bool - to hold whether the window is maximized or not. If you want to store more information then a different type or structure will be needed.

Initialise the first two to 0 and the second two to the default size of your application, and the last one to false.

Create a Window_OnSourceInitialized event handler and add the following:

this.Top = Properties.Settings.Default.Top;
this.Left = Properties.Settings.Default.Left;
this.Height = Properties.Settings.Default.Height;
this.Width = Properties.Settings.Default.Width;
// Very quick and dirty - but it does the job
if (Properties.Settings.Default.Maximized)
{
    WindowState = WindowState.Maximized;
}

NOTE: The set window placement needs to go in the on source initialised event of the window not the constructor, otherwise if you have the window maximised on a second monitor, it will always restart maximised on the primary monitor and you won't be able to access it.

Create a Window_Closing event handler and add the following:

if (WindowState == WindowState.Maximized)
{
    // Use the RestoreBounds as the current values will be 0, 0 and the size of the screen
    Properties.Settings.Default.Top = RestoreBounds.Top;
    Properties.Settings.Default.Left = RestoreBounds.Left;
    Properties.Settings.Default.Height = RestoreBounds.Height;
    Properties.Settings.Default.Width = RestoreBounds.Width;
    Properties.Settings.Default.Maximized = true;
}
else
{
    Properties.Settings.Default.Top = this.Top;
    Properties.Settings.Default.Left = this.Left;
    Properties.Settings.Default.Height = this.Height;
    Properties.Settings.Default.Width = this.Width;
    Properties.Settings.Default.Maximized = false;
}

Properties.Settings.Default.Save();

This will fail if the user makes the display area smaller - either by disconnecting a screen or changing the screen resolution - while the application is closed so you should add a check that the desired location and size is still valid before applying the values.


Actually you don't need to use code-behind to do that (except for saving the settings). You can use a custom markup extension to bind the window size and position to the settings like this :

<Window x:Class="WpfApplication1.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:my="clr-namespace:WpfApplication1"
        Title="Window1"
        Height="{my:SettingBinding Height}"
        Width="{my:SettingBinding Width}"
        Left="{my:SettingBinding Left}"
        Top="{my:SettingBinding Top}">

You can find the code for this markup extension here : http://www.thomaslevesque.com/2008/11/18/wpf-binding-to-application-settings-using-a-markup-extension/


The "long form" binding that Thomas posted above requires almost no coding, just make sure you have the namespace binding:

<Window x:Class="WpfApplication1.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:p="clr-namespace:WpfApplication1.Properties"
        Title="Window1"
        Height="{Binding Source={x:Static p:Settings.Default}, Path=Height, Mode=TwoWay}"
        Width="{Binding Source={x:Static p:Settings.Default}, Path=Width, Mode=TwoWay}"
        Left="{Binding Source={x:Static p:Settings.Default}, Path=Left, Mode=TwoWay}"
        Top="{Binding Source={x:Static p:Settings.Default}, Path=Top, Mode=TwoWay}">

Then to save on the code-behind:

private void frmMain_Closed(object sender, EventArgs e)
{
    Properties.Settings.Default.Save();
}

While you can "roll your own" and manually save the settings somewhere, and in general it will work, it is very easy to not handle all of the cases correctly. It is much better to let the OS do the work for you, by calling GetWindowPlacement() at exit and SetWindowPlacement() at startup. It handles all of the crazy edge cases that can occur (multiple monitors, save the normal size of the window if it is closed while maximized, etc.) so that you don't have to.

This MSDN Sample shows how to use these with a WPF app. The sample isn't perfect (the window will start in the upper left corner as small as possible on first run, and there is some odd behavior with the Settings designer saving a value of type WINDOWPLACEMENT), but it should at least get you started.

Tags:

Windows

C#

.Net

Wpf