DragMove() and Maximize

14
我在WPF中使用自定义窗口(AllowTransparency,WindowStyle=None)时遇到问题。 DragMove()方法可以正常工作,但当我最大化窗口或Windows 7 Aero Snap自动将其最大化时,此方法完全不起作用。因此,我无法通过鼠标拖动取消窗口捕捉并将其状态返回到WindowState.Normal。 左侧和右侧的Aero Snap正常工作,我可以轻松地捕捉和取消捕捉窗口。 但是在最大化时,除Win+Down组合键外,没有任何功能。也许有人知道如何解决这个问题,或者在哪里可以找到其他方法来正确地使用DragMove并且支持Aero Snap功能?
6个回答

17

这是我的方法。尝试让它更短)))

private void InitHeader()
{
    var border = Find<Border>("borderHeader");
    var restoreIfMove = false;

    border.MouseLeftButtonDown += (s, e) =>
    {
        if (e.ClickCount == 2)
        {
            if ((ResizeMode == ResizeMode.CanResize) ||
                (ResizeMode == ResizeMode.CanResizeWithGrip))
            {
                SwitchState();
            }
        }
        else
        {
            if (WindowState == WindowState.Maximized)
            {
                restoreIfMove = true;
            }

            DragMove();
        }
    };
    border.MouseLeftButtonUp += (s, e) =>
    {
        restoreIfMove = false;
    };
    border.MouseMove += (s, e) =>
    {
        if (restoreIfMove)
        {
            restoreIfMove = false;
            var mouseX = e.GetPosition(this).X;
            var width = RestoreBounds.Width;
            var x = mouseX - width / 2;

            if (x < 0)
            {
                x = 0;
            }
            else
            if (x + width > screenSize.X)
            {
                x = screenSize.X - width;
            }

            WindowState = WindowState.Normal;
            Left = x;
            Top = 0;
            DragMove();
        }
    };
}

private void SwitchState()
{
    switch (WindowState)
    {
        case WindowState.Normal:
        {
            WindowState = WindowState.Maximized;
            break;
        }
        case WindowState.Maximized:
        {
            WindowState = WindowState.Normal;
            break;
        }
    }
}

我使用本地方法来获取屏幕尺寸。


@ groaner,你能指出你使用的screenSize本地方法吗? - egfconnor
每次执行DragMove()时,我需要评估Mouse.LeftButton == MouseButtonState.Pressed,以避免出现“仅在主鼠标按钮按下时才能调用DragMove”的错误。此外,在评估新的x位置(var x = mouseX - width / 2; line)之前,WindowState应该设置为WindowState.Normal。通过这些修改,程序可以完美地运行,谢谢! - daro
最好与Anthony M的解决方案结合使用。谢谢! - hansmei

15

Groaner的解决方案在多监视器设置中无法正常工作,特别是当主要监视器不是最左边的时。

这是基于他的解决方案的我的解决方案,可以正确处理单个或多个监视器设置。在此代码中,“rctHeader”是在XAML中定义的矩形。

    private bool mRestoreIfMove = false;


    public MainWindow()
    {
        InitializeComponent();
    }


    private void SwitchWindowState()
    {
        switch (WindowState)
        {
            case WindowState.Normal:
                {
                    WindowState = WindowState.Maximized;
                    break;
                }
            case WindowState.Maximized:
                {
                    WindowState = WindowState.Normal;
                    break;
                }
        }
    }


    private void rctHeader_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        if (e.ClickCount == 2)
        {
            if ((ResizeMode == ResizeMode.CanResize) || (ResizeMode == ResizeMode.CanResizeWithGrip))
            {
                SwitchWindowState();
            }

            return;
        }

        else if (WindowState == WindowState.Maximized)
        {
            mRestoreIfMove = true;
            return;
        }

        DragMove();
    }


    private void rctHeader_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        mRestoreIfMove = false;
    }


    private void rctHeader_MouseMove(object sender, MouseEventArgs e)
    {
        if (mRestoreIfMove)
        {
            mRestoreIfMove = false;

            double percentHorizontal = e.GetPosition(this).X / ActualWidth;
            double targetHorizontal = RestoreBounds.Width * percentHorizontal;

            double percentVertical = e.GetPosition(this).Y / ActualHeight;
            double targetVertical = RestoreBounds.Height * percentVertical;

            WindowState = WindowState.Normal;

            POINT lMousePosition;
            GetCursorPos(out lMousePosition);

            Left = lMousePosition.X - targetHorizontal;
            Top = lMousePosition.Y - targetVertical;

            DragMove();
        }
    }



    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool GetCursorPos(out POINT lpPoint);


    [StructLayout(LayoutKind.Sequential)]
    public struct POINT
    {
        public int X;
        public int Y;

        public POINT(int x, int y)
        {
            this.X = x;
            this.Y = y;
        }
    }


}

这真的很有帮助!感谢。 - slow

13

在WPF中,我强烈建议在恢复窗口之前使用Control.PointToScreen而不是使用Window.DragMove。PointToScreen还可以处理多监视器设置。这将简化恢复过程如下:

    private void OnMouseLeftButtonDown( object sender, MouseButtonEventArgs e )
    {
        if( e.ClickCount == 2 )
        {
            if( ResizeMode != ResizeMode.CanResize && 
                ResizeMode != ResizeMode.CanResizeWithGrip )
            {
                return;
            }

            WindowState = WindowState == WindowState.Maximized
                ? WindowState.Normal
                : WindowState.Maximized;
        }
        else
        {
            mRestoreForDragMove = WindowState == WindowState.Maximized;
            DragMove();
        }
    }

    private void OnMouseMove( object sender, MouseEventArgs e )
    {
        if( mRestoreForDragMove )
        {
            mRestoreForDragMove = false;

            var point = PointToScreen( e.MouseDevice.GetPosition( this ) );

            Left = point.X - ( RestoreBounds.Width * 0.5 );
            Top = point.Y;

            WindowState = WindowState.Normal;

            DragMove();
        }
    }

    private void OnMouseLeftButtonUp( object sender, MouseButtonEventArgs e )
    {
        mRestoreForDragMove = false;
    }

    private bool mRestoreForDragMove;

1
这个解决方案非常完美,正是我所需要的。感谢您的分享。 - Al0x
1
与其他解决方案相比,这个是最好的工作方式 - 它有一些小缺陷,但它仍然非常好地工作。 - Christian Ivicevic

7
有点晚了,但我的代码更简单,我会在这里放上来。 左右吸附正常工作,但当窗口最大化或吸附到屏幕上边界并最大化时,DragMove方法将不起作用!所以这就是我做的:
只需像这样处理要拖动的元素上的Mouse_Down事件:
private void TitleBar_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    if (WindowState == WindowState.Maximized)
    {
        var point = PointToScreen(e.MouseDevice.GetPosition(this));

        if (point.X <= RestoreBounds.Width / 2)
            Left = 0;

        else if (point.X >= RestoreBounds.Width)
            Left = point.X - (RestoreBounds.Width - (this.ActualWidth - point.X));

        else
            Left = point.X - (RestoreBounds.Width / 2);

        Top = point.Y - (((FrameworkElement)sender).ActualHeight / 2);
        WindowState = WindowState.Normal;
    }
    DragMove(); 
}

希望这能对某些人有所帮助!


有时候窗口会回到正常状态,但是不会停留在鼠标位置上,这真的很恼人。 - Christian Ivicevic

2

DragMove()方法只能在窗体的标题栏中使用,因此请使用以下代码:

最初的回答:

[DllImport("user32.dll")]
public static extern IntPtr SendMessage(IntPtr hWnd, int wMsg, int wParam, int lParam);

public static void StartDrag(Window window)
{
    WindowInteropHelper helper = new WindowInteropHelper(window);
    SendMessage(helper.Handle, 161, 2, 0);
}

请不要忘记添加 System.Windows.Interop。最初的回答包含此信息。

0

1
很抱歉,但这篇博客文章几乎没有用处,它实际上需要拆开你在博客文章中提到的整个项目,并取出所需的内容。 - CularBytes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接