【问题标题】:WPF draggable and clickable buttonWPF 可拖动和可点击的按钮
【发布时间】:2020-02-12 22:49:23
【问题描述】:

我有一个无边界、透明的Window,只有一个Button

My fancy button looks like this

预期的行为是:

  • 当我单击并拖动按钮时,按钮必须跟随光标。
  • 当我只单击 Button 时,MouseDown、PreviewMouseDown 事件或 Command 绑定应该会引发。

起初我尝试在 PreviewMouseDown 事件上调用 DragMove(),但这会阻止点击事件。现在我的想法是:我在鼠标按下后设置了 100 毫秒的延迟。如果时间过去了,按钮将被拖动,否则只是单击。

代码

private bool _dragging;
private Point startpos;
CancellationTokenSource cancellation;

private void Button_PreviewMouseMove(object sender, MouseEventArgs e)
{
    if (_dragging && e.LeftButton == MouseButtonState.Pressed)
    {
        var currentpos = e.GetPosition(this);
        Left += currentpos.X - startpos.X;
        Top += currentpos.Y - startpos.Y;
    }
}

private async void Button_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
    if (e.ChangedButton != MouseButton.Left)
        return;

    _dragging = false;
    startpos = e.GetPosition(this);

    cancellation?.Cancel();
    cancellation = new CancellationTokenSource();

    await Task.Delay(100, cancellation.Token).ContinueWith(task =>
    {
        _dragging = !task.IsCanceled;
    });
}

private void Button_PreviewMouseUp(object sender, MouseButtonEventArgs e)
{
    if (_dragging)
    {
        _dragging = false;
        e.Handled = true;
    }

    cancellation?.Cancel();
}

基本上可以,但有一些错误:

  • 当我长时间按住鼠标按钮并松开时,单击将不起作用,因为 100 毫秒后拖动将处于活动状态。
  • 在我拖动按钮并单击ButtonWindow 控件之外的任意位置后,将引发 PreviewMouseDown 和 PreviewMouseUp 事件。不知道为什么??

有人有更好的解决方案吗?

【问题讨论】:

    标签: c# wpf click drag


    【解决方案1】:

    对于您的第一个问题:
    当您的按钮被按下但未移动时,您必须处理这种情况。我认为更好的方法(而不是 100 毫秒延迟)是指定一个最小移动阈值,超过该阈值拖动将开始。
    你可以这样做:

    private const double _dragThreshold = 1.0;
    private bool _dragging;
    private Point startpos;
    CancellationTokenSource cancellation;
    
    private void Button_PreviewMouseMove(object sender, MouseEventArgs e)
    {
        var currentpos = e.GetPosition(this);
        var delta = currentpos - startpos;
        if ((delta.Length > _dragThreshold || _dragging) && e.LeftButton == MouseButtonState.Pressed)
        {
            _dragging = true;
            Left += currentpos.X - startpos.X;
            Top += currentpos.Y - startpos.Y;
        }
    }
    
    private async void Button_PreviewMouseDown(object sender, MouseButtonEventArgs e)
    {
        if (e.ChangedButton != MouseButton.Left)
            return;
    
        _dragging = false;
        startpos = e.GetPosition(this);
    
        cancellation?.Cancel();
        cancellation = new CancellationTokenSource();
    }
    

    对于您的第二个问题:按钮将在鼠标按下事件时捕获鼠标。
    完成拖动后,您需要使用ReleaseMouseCapture 方法释放捕获的鼠标。

    private void Button_PreviewMouseUp(object sender, MouseButtonEventArgs e)
    {
        if (_dragging)
        {
            _dragging = false;
            e.Handled = true;
            var button = sender as Button;
            button.ReleaseMouseCapture();
        }
    
        cancellation?.Cancel();
    }
    

    【讨论】:

    • 谢谢它有效,我不知道 MouseCaptureRelesae。你有我的绿色支票。
    猜你喜欢
    • 2014-11-11
    • 2011-04-27
    • 2015-09-26
    • 1970-01-01
    • 2015-08-30
    • 2014-05-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多