【问题标题】:DragMove() and MaximizeDragMove() 和最大化
【发布时间】:2012-07-27 01:52:36
【问题描述】:

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

【问题讨论】:

    标签: wpf drag move maximize


    【解决方案1】:

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

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

    (为了获取 screenSize 我使用本地方法)

    【讨论】:

    • @groaner 你能指出你使用的 screenSize 原生方法吗?
    • 我需要评估 if Mouse.LeftButton == MouseButtonState.Pressed 每次我执行 DragMove();避免“只能在主鼠标按钮按下时调用 DragMove”。此外,在评估新的 x 位置(var x = mouseX - width / 2; line)之前,应将 WindowState 设置为 WindowState.Normal。有了这些修改就完美了,谢谢!
    • 与 Anthony M 的解决方案结合使用效果最佳。谢谢!
    【解决方案2】:

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

    【讨论】:

    • 这真的很有帮助!谢谢。
    【解决方案3】:

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

    【讨论】:

    • 这个解决方案完美运行,正是我想要的。谢谢分享。
    • 与其他解决方案相比,这是效果最好的 - 它有一些小缺陷,但仍然非常好用。
    【解决方案4】:

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

    希望对大家有所帮助!

    【讨论】:

    • 偶尔会出现窗口恢复到正常状态但没有锚定到鼠标的情况,这真的很烦人。
    【解决方案5】:

    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

    【讨论】:

      【解决方案6】:

      【讨论】:

      • 很抱歉,这篇博文几乎没用,它实际上需要撕开你在博文中提到的整个项目并找出需要的东西。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-04-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-02
      相关资源
      最近更新 更多