Запомнить положение, размер и состояние окна [при выравнивании Win + Arrow] (с несколькими мониторами)

В нашем проекте мы сохраняем размер окна, положение и параметры свертывания/разворачивания, поэтому мы можем открыть окно в том же месте и с тем же размером при повторном его открытии. Все это работает довольно хорошо, используя класс Window-Behavior, найденный внизу этого поста.

Однако проблема заключается в том, что мы используем кнопку Win + стрелку; Это выравнивает экран по краю экрана, но это неправильно сохраняется в поведении. Вместо этого он сохраняет положение и размер экрана до того, как я использовал стрелку Win +, чтобы выровнять его, и это положение снова открывается.

Я пытался использовать Left, Top, ActualWidth и ActualHeight окна в методе SaveWindowState (Примечание: AssociatedObject в этом методе — это окно). сохранение правого и левого с использованием ActualWidth, ActualHeight и текущей ширины/высоты экрана (при использовании нескольких мониторов) также немного мучительно.

Итак, есть ли способ сохранить правильное положение и размер в настройках окна, когда пользователь использует Win + стрелка для выравнивания окна, а затем закрывает его?

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
}

person Kevin Cruijssen    schedule 08.01.2015    source источник
comment
Хотите знать, почему вы работаете с импортом user32.dll, а не с прямым доступом к экземпляру окна?   -  person Herdo    schedule 08.01.2015
comment
Да, Aero Snap очень причудливый. Самая большая проблема заключается в том, что для этого нет ни уведомления, ни способа привязаться к winapi, размещение окна не обновляется. И остерегайтесь странной системы координат, которую использует Get/SetWindowPlacement, она вычитает панели задач. Лучше всего избегать полностью.   -  person Hans Passant    schedule 08.01.2015


Ответы (1)


Вы пробовали экземпляр System.Windows.Window вместо p/invoke ? Я использую два простых метода для сохранения и установки положения окна с помощью этого класса, и он отлично работает с пикселями в разных приложениях, архитектурах, клиентах, ОС Windows, с Aero или без него...

void SetWindowPosition()
{
    this.Left = Settings.Default.WindowPositionLeft;
    this.Top = Settings.Default.WindowPositionTop;
}
void SaveWindowPosition()
{
    Settings.Default.WindowPositionTop = this.Top;
    Settings.Default.WindowPositionLeft = this.Left;
    Settings.Default.Save();
}

Или я что-то упускаю?

person DKH    schedule 06.09.2017
comment
Или я что-то упускаю? Честно говоря, я понятия не имею, что я пробовал/не пробовал. Я задавал вопрос более 2,5 лет назад. ;) В настоящее время я даже не занимаюсь ежедневной разработкой на .NET C#. - person Kevin Cruijssen; 06.09.2017
comment
Я все время забываю проверять даты тем :D Тогда получайте удовольствие от своих новых проектов! - person DKH; 07.09.2017