In our project we save the Window Size, Position and Minimized/Maximized Settings, so we can open the window at the exact same spot and size when we re-open it. All this is working quite well, using the Window-Behavior
-class found at the bottom of this post.
The problem however, is when we use the Win-button + an arrow; This aligns the screen to the side of the screen, but this isn't correctly saved in the behavior. Instead, it saves the position and size of the screen before I used the Win + arrow to align it, and that is the position it is opened again.
I've tried to use the Window's Left
, Top
, ActualWidth
and ActualHeight
in the SaveWindowState
-method (Note: The AssociatedObject
in this method is the Window.) But the Left
and Top
seem to be off by about 20-40 pixels, and saving the Right and Left using the ActualWidth
, ActualHeight
and current screen width/height (when using multiple monitors) is also a bit of a pain.
So, is there any way to save the correct position and size in the Window Settings when a user uses Win + arrow to align the Window and then closes it?
WindowSettingsBehavior
:
using System;
using System.ComponentModel;
using System.Configuration;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interactivity;
using System.Windows.Interop;
namespace NatWa.MidOffice.Behaviors
{
/// <summary>
/// Persists a Window's Size, Location and WindowState to UserScopeSettings
/// </summary>
public class WindowSettingsBehavior : Behavior<Window>
{
[DllImport("user32.dll")]
static extern bool SetWindowPlacement(IntPtr hWnd, [In] ref Windowplacement lpwndpl);
[DllImport("user32.dll")]
static extern bool GetWindowPlacement(IntPtr hWnd, out Windowplacement lpwndpl);
// ReSharper disable InconsistentNaming
const int SW_SHOWNORMAL = 1;
const int SW_SHOWMINIMIZED = 2;
// ReSharper restore InconsistentNaming
internal class WindowApplicationSettings : ApplicationSettingsBase
{
public WindowApplicationSettings(WindowSettingsBehavior windowSettingsBehavior)
: base(windowSettingsBehavior.AssociatedObject.GetType().FullName)
{
}
[UserScopedSetting]
public Windowplacement? Placement
{
get
{
if (this["Placement"] != null)
{
return ((Windowplacement)this["Placement"]);
}
return null;
}
set
{
this["Placement"] = value;
}
}
}
/// <summary>
/// Load the Window Size Location and State from the settings object
/// </summary>
private void LoadWindowState()
{
Settings.Reload();
if (Settings.Placement == null) return;
try
{
// Load window placement details for previous application session from application settings.
// If window was closed on a monitor that is now disconnected from the computer,
// SetWindowPlacement will place the window onto a visible monitor.
var wp = Settings.Placement.Value;
wp.length = Marshal.SizeOf(typeof(Windowplacement));
wp.flags = 0;
wp.showCmd = (wp.showCmd == SW_SHOWMINIMIZED ? SW_SHOWNORMAL : wp.showCmd);
var hwnd = new WindowInteropHelper(AssociatedObject).Handle;
SetWindowPlacement(hwnd, ref wp);
}
catch (Exception ex)
{
Debug.WriteLine("Failed to load window state:\r\n{0}", ex);
}
}
/// <summary>
/// Save the Window Size, Location and State to the settings object
/// </summary>
private void SaveWindowState()
{
Windowplacement wp;
var hwnd = new WindowInteropHelper(AssociatedObject).Handle;
GetWindowPlacement(hwnd, out wp);
Settings.Placement = wp;
Settings.Save();
}
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.Closing += WindowClosing;
AssociatedObject.SourceInitialized += WindowSourceInitialized;
}
private void WindowSourceInitialized(object sender, EventArgs e)
{
LoadWindowState();
}
private void WindowClosing(object sender, CancelEventArgs e)
{
SaveWindowState();
AssociatedObject.Closing -= WindowClosing;
AssociatedObject.SourceInitialized -= WindowSourceInitialized;
}
private WindowApplicationSettings _windowApplicationSettings;
internal virtual WindowApplicationSettings CreateWindowApplicationSettingsInstance()
{
return new WindowApplicationSettings(this);
}
[Browsable(false)]
internal WindowApplicationSettings Settings
{
get { return _windowApplicationSettings
?? (_windowApplicationSettings = CreateWindowApplicationSettingsInstance()); }
}
}
#region Save position classes
[Serializable]
[StructLayout(LayoutKind.Sequential)]
public struct Rect
{
private int _left;
private int _top;
private int _right;
private int _bottom;
public Rect(int left, int top, int right, int bottom)
{
_left = left;
_top = top;
_right = right;
_bottom = bottom;
}
public override bool Equals(object obj)
{
if (!(obj is Rect)) return base.Equals(obj);
var rect = (Rect)obj;
return rect._bottom == _bottom &&
rect._left == _left &&
rect._right == _right &&
rect._top == _top;
}
public override int GetHashCode()
{
return _bottom.GetHashCode() ^
_left.GetHashCode() ^
_right.GetHashCode() ^
_top.GetHashCode();
}
public static bool operator ==(Rect a, Rect b)
{
return a._bottom == b._bottom &&
a._left == b._left &&
a._right == b._right &&
a._top == b._top;
}
public static bool operator !=(Rect a, Rect b)
{
return !(a == b);
}
public int Left
{
get { return _left; }
set { _left = value; }
}
public int Top
{
get { return _top; }
set { _top = value; }
}
public int Right
{
get { return _right; }
set { _right = value; }
}
public int Bottom
{
get { return _bottom; }
set { _bottom = value; }
}
}
[Serializable]
[StructLayout(LayoutKind.Sequential)]
public struct Point
{
private int _x;
private int _y;
public Point(int x, int y)
{
_x = x;
_y = y;
}
public int X
{
get { return _x; }
set { _x = value; }
}
public int Y
{
get { return _y; }
set { _y = value; }
}
public override bool Equals(object obj)
{
if (!(obj is Point)) return base.Equals(obj);
var point = (Point)obj;
return point._x == _x && point._y == _y;
}
public override int GetHashCode()
{
return _x.GetHashCode() ^ _y.GetHashCode();
}
public static bool operator ==(Point a, Point b)
{
return a._x == b._x && a._y == b._y;
}
public static bool operator !=(Point a, Point b)
{
return !(a == b);
}
}
[Serializable]
[StructLayout(LayoutKind.Sequential)]
public struct Windowplacement
{
public int length;
public int flags;
public int showCmd;
public Point minPosition;
public Point maxPosition;
public Rect normalPosition;
}
#endregion
}
user32.dll
import, rather then accessing the window instance directly? – Disconnect