wpf DragMove() 和最大化

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11703833/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 04:46:04  来源:igfitidea点击:

DragMove() and Maximize

wpfdragmovemaximize

提问by Igor Ostancov

I have a problem with my custom window (AllowTransparency, WindowStyle=None) in WPF. DragMove() method works good, but when I maximize window, or it maximizing automatically by Windows 7 Aero Snap, this method does not work at all. So I can't unsnap window with mouse drag and return it state to WindowState.Normal. Left and Right Aero Snap works good, I can snap and unsnap window without a problem. But when it maximized, nothing works except Win+Down combination. Maybe somebody knows how to solve this problem or where can I find other ways to do proper DragMove of custom window with working Aero Snap features?

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

回答by groaner

Here is my method. Try make it shorter )))

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

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

(To get screenSize I use native methods)

(为了获得 screenSize 我使用本机方法)

回答by leebickmtu

Groaner's solution does not function properly with multiple monitor setups, especially where the primary monitor is not the left-most.

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

Here is my solution based on his which handles single or multiple monitor setups properly. In this code 'rctHeader' is a Rectangle defined in the XAML.

这是我基于他的解决方案,它可以正确处理单个或多个显示器设置。在这段代码中,'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;
        }
    }


}

回答by Anthony M.

In WPF I would highly recommend using Control.PointToScreenwhen restoring the window before your Window.DragMove. PointToScreen will also handle multiple monitor setups. This would simplify the restore to the following:

在 WPF 中,我强烈建议在Window.DragMove之前恢复窗口时使用Control.PointToScreen。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;

回答by Amir Mahdi Nassiri

A little late for another answer, but my code was simpler so I'll put it here. As you men the left and right snapping works just fine but when the window is Maximized or snaps to upper screen bounds and maximizes, the DragMove method will not work!

另一个答案有点晚了,但我的代码更简单,所以我把它放在这里。正如你们一样,左右捕捉工作得很好,但是当窗口最大化或捕捉到屏幕上边界并最大化时,DragMove 方法将不起作用!



Just handle the Mouse_Down Event on the element you want to drag with like this:

只需在要拖动的元素上处理 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(); 
}

I hope it helps someone!

我希望它可以帮助某人!

回答by Selastin George

The DragMove() method only works in the titlebar of the form so use:

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

Dont forget to add System.Windows.Interop

不要忘记添加 System.Windows.Interop