Caves Travel Diving Graphics Mizar Texts Cuisine Lemkov Contact Map RSS Polski
Trybiks' Dive Texts Programming Saving / restoring window placements in .NET YAC Software
  Back

List

Charsets

Charts

DBExpress

Delphi

HTML

Intraweb

MSTest

PHP

Programming

R

Rhino Mocks

Software

Testing

UI Testing

VB.NET

VCL

WPF

Saving / restoring window placements in .NET
It seems that saving window positions and sizes (including the application's main window location) should be easy enough. But even now, after so many years of Windows programming, people get it wrong. We need to remember about changing screen resolutions, switching from multiple to single monitors, connecting to a projector, etc. Saving the current window's location just ain't gonna do the trick...

The key to the solution is the pair of Windows API functions: GetWindowPlacement and SetWindowPlacement.

Something like this - saving and restoring a Window's placement (GetSetting/SetSetting are functions that load/save settings through some utility class; LEFT_ID, etc. are just string constants used to define keys under which settings are saved):
  Public Sub LoadWindowPlacement(ByVal key As String, ByVal window As Window)
    Dim windowPlacement As WindowPlacement = GetWindowPlacement(window)
  
    Dim restoredPosition As New IntegerRect(
      GetSetting(Of Integer)(key + LEFT_ID, windowPlacement.NormalPosition.Left),
      GetSetting(Of Integer)(key + TOP_ID, windowPlacement.NormalPosition.Top),
      GetSetting(Of Integer)(key + WIDTH_ID, windowPlacement.NormalPosition.Width),
      GetSetting(Of Integer)(key + HEIGHT_ID, windowPlacement.NormalPosition.Height))
  
    windowPlacement.NormalPosition = restoredPosition
    windowPlacement.ShowCommand =
      GetSetting(Of Integer)(key + SHOW_COMMAND_ID, SHOW_MAXIMIZED)
  
    SetWindowPlacement(window, windowPlacement)
  End Sub
  
  Public Sub SaveWindowPlacement(ByVal key As String, ByVal window As Window)
    Dim windowPlacement As WindowPlacement = GetWindowPlacement(window)
  
    SetSetting(Of Integer)(key + HEIGHT_ID, windowPlacement.NormalPosition.Height)
    SetSetting(Of Integer)(key + WIDTH_ID, windowPlacement.NormalPosition.Width)
    SetSetting(Of Integer)(key + TOP_ID, windowPlacement.NormalPosition.Top)
    SetSetting(Of Integer)(key + LEFT_ID, windowPlacement.NormalPosition.Left)
    SetSetting(Of Integer)(key + SHOW_COMMAND_ID, windowPlacement.ShowCommand)
  End Sub
Note that, in the above, we set save/load the NormalPosition (the location of the window in restored state), and handle minimization / maximization separately.

What needs to be done still is we need methods to interface with the Windows API; first, several structures:
  <StructLayout(LayoutKind.Sequential)>
  Public Structure IntegerPoint
  
    Public Property X As Integer
    Public Property Y As Integer
  
  End Structure
  
  <StructLayout(LayoutKind.Sequential)>
  Public Structure IntegerRect
  
    Public Property Left As Integer
    Public Property Top As Integer
    Public Property Width As Integer
    Public Property Height As Integer
  
  End Structure
  
  <StructLayout(LayoutKind.Sequential)>
  Public Structure WindowPlacement
  
    Public Property Length As Integer
    Public Property Flags As Integer
    Public Property ShowCommand As Integer
    Public Property MinPosition As IntegerPoint
    Public Property MaxPosition As IntegerPoint
    Public Property NormalPosition As IntegerRect
  
  End Structure
The last structure is the important one - you'll find the description here.

Next, for the functions:
  Public NotInheritable Class WindowUtilities
  
    Private Sub New()
    End Sub
  
    Public Const SHOW_NORMAL As Integer = 1
    Public Const SHOW_MINIMIZED As Integer = 2
    Public Const SHOW_MAXIMIZED As Integer = 3
  
    Public Shared Function GetWindowPlacement(
      ByVal window As Window) As WindowPlacement
  
      Dim placement As WindowPlacement
      SafeNativeMethods.GetWindowPlacement(
        New WindowInteropHelper(window).Handle, placement)
      Return placement
    End Function
  
    Public Shared Sub SetWindowPlacement(
      ByVal window As Window, ByVal placement As WindowPlacement)
  
      SafeNativeMethods.SetWindowPlacement(
        New WindowInteropHelper(window).Handle, placement)
    End Sub
  
  End Class
  
  Friend NotInheritable Class SafeNativeMethods
  
    Private Sub New()
    End Sub
  
    <DllImport("user32.dll")>
    Public Shared Function GetWindowPlacement(
      ByVal handle As IntPtr, ByRef placement As WindowPlacement)
      As <MarshalAs(UnmanagedType.Bool)> Boolean
    End Function
  
    <DllImport("user32.dll")>
    Public Shared Function SetWindowPlacement(
      ByVal handle As IntPtr, ByRef placement As WindowPlacement)
      As <MarshalAs(UnmanagedType.Bool)> Boolean
    End Function
  
  End Class
And this is quite enough for the application to behave correctly between sessions, regardless what happens with the screen's resolution, Window's task bar's position, or multi-monitor setup.

HTH

Top

Comments
Alas!
No comments yet...

Top

Add a comment (fields with an asterisk are required)
Name / nick *
Mail (will remain hidden) *
Your website
Comment (no tags) *
Enter the text displayed below *
 

Top

Tags

Programming

VB.NET


Related pages

AssertWasCalled and Methods Called Multiple Times

AssertWas[Not]Called and Object Properties

Rhino Mocks's AssertWasNotCalled

TFS - The underlying connection was closed: an unexpected error occurred on a receive.

PrivateObject and Out/ByRef parameters

WCF - The underlying connection was closed: an unexpected error occurred on a receive.

PrivateObject, WithEvents, and generics

Accessing private members of base classes

CA1800:DoNoCastUnnecessarily

PrivateObject and WithEvents

The creator of this fault did not specify a Reason.

Accessing private and protected members - PrivateObject and PrivateType

Checking Property Change Notifications

Rhino Mocks's AssertWasCalled in VB.NET

First steps with Rhino Mocks (in VB.NET)

Meaningful identifiers

Public fields vs. properties

A Case for FreeAndNIL

Random()'s Determinism

Rounding and precision on the 8087 FPU

Controlling Conditional Defines and Compilation Switches

Registering Extensions

Accessing Protected Members