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
}