Помните положение, размер и состояние окна [при Win + выравнивание по стрелке] (с несколькими мониторами)
В нашем проекте мы сохраняем Размер окна, Положение и Свернутые / развернутые параметры, чтобы мы могли открыть окно в том же месте и размере при повторном его открытии. Все это работает довольно хорошо, используя Window-Behavior
-класс найден внизу этого поста.
Проблема, однако, в том, когда мы используем кнопку Win + стрелка; Это выравнивает экран по краям экрана, но это неправильно сохраняется в поведении. Вместо этого он сохраняет положение и размер экрана до того, как я использовал стрелку Win +, чтобы выровнять его, и это позиция, которую он снова открывает.
Я пытался использовать окна Left
, Top
, ActualWidth
а также ActualHeight
в SaveWindowState
-метод (Примечание: AssociatedObject
в этом методе окно.) Но Left
а также Top
кажется, примерно на 20-40 пикселей, и сохранение правого и левого с помощью 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
}
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();
}
Или я что-то упустил?