WPF可拖动和可点击按钮

问题描述 投票:0回答:1

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

My fancy button looks like this

预期的行为是:

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

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

代码

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个回答
0
投票

第一个问题:当您按下按钮但不移动时,您必须处理这种情况。我认为一种更好的方法(而不是100ms的延迟)将是指定最小移动阈值,在此阈值以上将开始拖动。您可以这样做:

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();
}
© www.soinside.com 2019 - 2024. All rights reserved.