2015-01-08 2 views
7

В нашем проекте мы сохраняем размер окна, положение и минимизированные/максимальные настройки, чтобы мы могли открыть окно в том же месте и когда мы его снова открываем. Все это работает достаточно хорошо, используя класс Window-Behavior, найденный в нижней части этой публикации.Помните расположение, размер и состояние окна [при выравнивании Win + Arrow] (с несколькими мониторами)

Проблема, однако, заключается в использовании кнопки 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

Хотите узнать, почему вы работаете с импортом 'user32.dll', а не напрямую обращаться к экземпляру окна? – Herdo

+2

Да, Aero Snap очень изворотливый. Самая большая проблема заключается в том, что для этого нет никакого уведомления или способа привязки к winapi, размещение окна не обновляется. И остерегайтесь нечетной системы координат, которую использует Get/SetWindowPlacement, вычитает панели задач. Лучше всего избегать. –

ответ

0

Вы пробовали System.Windows.Window экземпляр вместо p/invoke? Я использую два простых методов, чтобы сохранить и установить положение окна с помощью этого класса, и он работает на pixelperfectly дифферент приложения, архитектуры, клиентов, операционных систем 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(); 
} 

Или я что-то отсутствует ?

+0

«Я что-то не хватает?» «Я буду полностью честен, я абсолютно не знаю, что я/не пробовал. Я отправил этот вопрос более 2,5 лет назад. ;) В настоящее время я даже не разрабатываю в .NET C# больше на ежедневной основе. –

+0

Я продолжаю забывать проверить даты потоков: D Удачи в ваших новых проектах! – DarKalimHero

Смежные вопросы