DragMove()和Maximize

问题描述 投票:11回答:6

我在WPF中的自定义窗口(AllowTransparency,WindowStyle = None)有问题。 DragMove()方法效果很好,但是当我最大化窗口,或者它通过Windows 7 Aero Snap自动最大化时,此方法根本不起作用。所以我无法用鼠标拖动来取消窗口并将其状态返回到WindowState.Normal。左右Aero Snap工作正常,我可以快速捕捉和取消窗口。但是当它最大化时,除了Win + Down组合之外没有任何作用。也许有人知道如何解决这个问题,或者我在哪里可以通过工作的Aero Snap功能找到其他方法来实现自定义窗口的正确DragMove?

wpf drag move maximize
6个回答
14
投票

这是我的方法。尽量缩短)))

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;
        }
    }
}

(要获得屏幕尺寸,我使用原生方法)


12
投票

Groaner的解决方案无法在多个监视器设置下正常运行,尤其是在主监视器不是最左侧的情况下。

这是我的解决方案,基于他的正确处理单个或多个显示器设置。在此代码中,'rctHeader'是在XAML中定义的Rectangle。

    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;
        }
    }


}

7
投票

在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;

3
投票

另一个答案有点晚了,但我的代码更简单,所以我会把它放在这里。正如你所做的那样,左右对齐的工作正常,但是当窗口最大化或捕捉到上部屏幕边界并最大化时,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(); 
}

我希望它对某人有所帮助!



0
投票

Drag Move()方法仅适用于表单的标题栏,因此使用:

[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

© www.soinside.com 2019 - 2024. All rights reserved.