拖动 WPF 表单在桌面上移动

16
我正在尝试制作一个 C# WPF 表单,可以通过点击并用鼠标拖动它来移动屏幕。该窗体的特点是完全透明且只包含一个图像。这意味着窗口样式为无,不显示在任务栏中。因此,在应用程序运行时,你只能看到一个小图像 - 理想情况下,我希望能够通过按住鼠标左键并将其移动来拖动它到桌面上任何位置。
请问是否有简单的方法可以实现这一点,或者我是否忽略了内置的功能?
谢谢。

非常感谢,我已经寻找了2天这样的答案 :) - user921272
5个回答

22

之前的回答已经接近正确答案,但完整的示例代码如下:

   private void Window_MouseDown(object sender, MouseButtonEventArgs e)
    {
        if (e.LeftButton == MouseButtonState.Pressed)
        {
            DragMove();
        }
    }

3
仅需使用MouseLeftButtonDown,无需进行检查。 - Ed S.

20

您可以在窗口的鼠标按下事件中使用Window.DragMove方法。


文档中有一个关于DragMove方法的代码示例,它完全展示了您试图做的事情,但只包含三行代码 - 处理窗口的MouseLeftButtonDown事件,调用窗口上的DragMove方法。 - Josh

3
以下是一些简化的代码,可以拖动WPF窗体在屏幕上移动。你可能已经在不同的帖子中看到了一些这样的代码,我只是修改了它以适应拖动WPF窗体的需求。
请记住,我们需要在MouseLeftButtonDown时抓取表单位置,以便我们可以将鼠标指针定位在表单上与我们拖动它在屏幕上相同的位置。
您还需要添加以下引用以获取鼠标位置相对于屏幕的位置:System.Windows.Forms。
所需属性:
private bool _IsDragInProgress { get; set; }
private System.Windows.Point _FormMousePosition {get;set;}

代码:

        protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
        {
            this._IsDragInProgress = true;
            this.CaptureMouse();
            this._FormMousePosition = e.GetPosition((UIElement)this);
            base.OnMouseLeftButtonDown(e);
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            if (!this._IsDragInProgress)
                return;

            System.Drawing.Point screenPos = (System.Drawing.Point)System.Windows.Forms.Cursor.Position;
            double top = (double)screenPos.Y - (double)this._FormMousePosition.Y;
            double left = (double)screenPos.X - (double)this._FormMousePosition.X;
            this.SetValue(MainWindow.TopProperty, top);
            this.SetValue(MainWindow.LeftProperty, left);
            base.OnMouseMove(e);
        }

        protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
        {
            this._IsDragInProgress = false;
            this.ReleaseMouseCapture();
            base.OnMouseLeftButtonUp(e);
        }

很奇怪,但是在MouseDown事件中使用简单的DragMove()函数可以正常工作,直到用户将窗口移动到桌面的顶部(大约100个像素的顶部)。使用您的解决方案,我的表格可以放置在用户想要的任何地方。如果有人想知道,我的WPF表格的WindowStyle为None,操作系统为Windows 7。 - Vladimir Vlasov
这只会使窗口在将特定控件作为拖动表面时快速闪烁和跳动。是否有任何原因在一个方法中使用不同的Forms.Cursor.Position和另一个方法中使用e.GetPosition? - StingyJack
@StingyJack 表单应该被定位为拖动表面,不应允许控件如按钮拖动表单。关于使用 e.GetPositionSystem.Windows.Forms.Cursor.Position,您需要将 System.Windows.Forms.Cursor.Position 转换为 Point。它看起来像这样:this._FormMousePosition = new Point(System.Windows.Forms.Cursor.Position.X, System.Windows.Forms.Cursor.Position.Y); 这个方法可以工作,但是 WPF 表单在初始点击时会跳跃。this._FormMousePosition = e.GetPosition((UIElement)this); 不会导致表单跳跃。 - Agrejus

1
如果你和我一样想要对DoDragMove()有更多的控制 - 例如,让窗口始终停留在当前桌面的边界上,那么我已经做到了。
使用方法:
public partial class MainWindow : Window
{
    private WindowsDragger _dragger;

    public MainWindow()
    {
        InitializeComponent();
        _dragger = new WindowsDragger(this);
    }
}

帮助类:

class WindowsDragger
{
    private readonly Window _window;
    private Point _dragDelta;

    public WindowsDragger(Window window)
    {
        _window = window;

        _window.MouseLeftButtonDown += MouseLeftButtonDown;
        _window.MouseLeftButtonUp += MouseLeftButtonUp;
        _window.MouseMove += MouseMove;
    }

    void MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        _dragDelta = e.GetPosition(_window);
        Mouse.Capture(_window);
    }

    void MouseMove(object sender, MouseEventArgs e)
    {
        if (Equals(_window, Mouse.Captured))
        {
            var pos = _window.PointToScreen(e.GetPosition(_window));
            var verifiedPos = CoerceWindowBound(pos - _dragDelta);
            _window.Left = verifiedPos.X;
            _window.Top = verifiedPos.Y;
        }
    }

    void MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        if (Equals(_window, Mouse.Captured))
            Mouse.Capture(null);
    }

    private Vector CoerceWindowBound(Vector newPoint)
    {
        // Snap to the current desktop border
        var screen = WpfScreen.GetScreenFrom(_window);
        var wa = screen.WorkingArea;
        if (newPoint.X < wa.Top) newPoint.X = wa.Top;
        if (newPoint.Y < wa.Left) newPoint.Y = wa.Left;
        if (_window.Width + newPoint.X > wa.Right) newPoint.X = wa.Right - _window.Width;
        if (_window.Height + newPoint.Y > wa.Bottom) newPoint.Y = wa.Bottom - _window.Height;
        return newPoint;
    }
}

其中 WpfScreen 是从这里获取的:如何在 WPF 中获取当前屏幕的大小?


1
在Windows加载或网格加载事件中,您可以使用委托来触发DragMove()函数。
'private void Grid_Loaded(object sender, RoutedEventArgs e) {'
        this.MouseDown += delegate{DragMove();};

    }`

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