简体   繁体   中英

AvalonDock 2.0 Floating Window looses maximized state on MainWindow minimize / restore

I am trying to achieve a VS style MainWindow + docking content host on secondary monitors. Avalon dock does the job gracefully. Until minimizing the window, that is.

Upon restore, the maximized 'docking host"(LayoutAnchorablePane) resets it's size and location to the pre-maximizing ones.

This is because when maximizing an avalon dock LayoutAnchorablePane, the Property Changed event doesn't fire. Also, the floating width property doesn't get updated.

This is why my first try __

    public Window3()
    {
        InitializeComponent();

        // Intercept the minimize event and cancel it.
        this.SourceInitialized += OnSourceInitialized; 

    }

    private void OnSourceInitialized(object sender, EventArgs e)
    {
        var source = (HwndSource)PresentationSource.FromVisual(this);
        if (source != null) source.AddHook(HandleMessages);
    }

    //These store the location and size of Left - the Layout Anchorable to be placed on a sec monitor
    private Point _location;
    private Size _size;

    private IntPtr HandleMessages(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
    {
        if (msg != 0x0112 || ((int) wParam & 0xFFF0) != 0xF020) return IntPtr.Zero;
        //This means a minimize for the Main Window. Cancel it.
        handled = true;
        //Get the sec monitor anchorable size and location
        _location = new Point(Left.FloatingLeft, Left.FloatingTop);
        _size = new Size(Left.FloatingWidth, Left.FloatingHeight);

        //finally minimize the window
        WindowState = WindowState.Minimized;


        return IntPtr.Zero;
    } 

    private void Window3_OnStateChanged(object sender, EventArgs e)
    {
        //Restore the width and location for the sec monitor anchorable
        // Fail. Cry. Cry a lot...
        if (WindowState == WindowState.Maximized)
        {
            Left.FloatingLeft = _location.X;
            Left.FloatingTop = _location.Y;
            Left.FloatingWidth = _size.Width;
            Left.FloatingHeight = _size.Height;
        }
    }

__ doesn't work.

These maximize / restore events are unreachable. They're stored in Controls/Shell/SystemCommands.cs

    public static void MaximizeWindow(Window window)
    {
        Verify.IsNotNull(window, "window");
        _PostSystemCommand(window, SC.MAXIMIZE);
    }

    private static void _PostSystemCommand(Window window, SC command)
    {
        IntPtr hwnd = new WindowInteropHelper(window).Handle;
        if (hwnd == IntPtr.Zero || !NativeMethods.IsWindow(hwnd))
        {
            return;
        }

        NativeMethods.PostMessage(hwnd, WM.SYSCOMMAND, new IntPtr((int)command), IntPtr.Zero);
    }

I've read some tips on avalondock's codeplex discussion but I think they applied to previous versions and were no longer valid.

I am thinking of using user32 GetWindowRect and SetWindowPos to get the location and size on minimize and restore it on maximize.

But, i simply have no ideea how to get the handle for the floating anchorables.

Any suggestion , on the floater handle or otherwise, will be greatly appreciated. Thank you for your time.

I also had the same issues (also visible in the WPF Toolkit sample) and found a solution !

The general idea is to ignore WindowState changes sent by Windows and always restore internal state :

protected override void OnStateChanged(EventArgs e)
{
    // Windows sometimes send unwanted state changes (when minimizing application for instance)
    // We force internal state to be used
    WindowState = IsMaximized ? WindowState.Maximized : WindowState.Normal;
    base.OnStateChanged(e);
}

The WM_SYSCOMMAND was not well handled (the 0xFFF0 mask was missing) :

case Win32Helper.WM_SYSCOMMAND:
    int command = (int)wParam & 0xFFF0;
    if (command == Win32Helper.SC_MAXIMIZE || command == Win32Helper.SC_RESTORE)
    {
        UpdateMaximizedState(command == Win32Helper.SC_MAXIMIZE);
    }

I also updated the UpdateMaximizedState to also change internal state:

void UpdateMaximizedState( bool isMaximized )
{
    foreach( var posElement in Model.Descendents().OfType<ILayoutElementForFloatingWindow>() )
    {
        posElement.IsMaximized = isMaximized;
    }
    IsMaximized = isMaximized;
    WindowState = isMaximized ? WindowState.Maximized : WindowState.Normal;
}

As a side note, IsMaximized is now a get / set property :

public bool IsMaximized
{
    get { return (bool)GetValue(IsMaximizedProperty); }
    set
    {
        SetValue(IsMaximizedProperty, value);
        UpdatePositionAndSizeOfPanes();
    }
}

And that's it !

Julien Richard is right and for those who are facing the same issue, but doesn't know where to go in the AvalonDock source code for fixing it, I would like to point to the detailed solution reported here:

http://wpftoolkit.codeplex.com/workitem/22296

There are different scenarios where the Maxmimized state of a LauoutFloatingWindowControl will fail in AvalonDock depending on its version for example:

  • when an AvalonDock layout is deserialized
  • when the main window is restored from the taskbar
  • when dragging a maximized floating window

In my case, I've noticed the issue in AvalonDock v.2.6 and by following the istructions linked above along with checking the latest version of the file here in the repository I resolved the issue.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM