繁体   English   中英

实现WaitForMouseUp()函数的更好方法?

[英]A Better Way to Implement a WaitForMouseUp() Function?

我需要一个小的功能,该功能将等待释放鼠标左键,并且不会基于MouseUp event

在许多情况下,我们只需要为MouseUp event编写一个事件处理程序。
这很简单,而且有效。

但是,在某些情况下,使用MouseUp event将无用,
例如当我们已经在另一个 (不同的)事件处理程序中时,
并且在调用此事件处理程序时可能会按下鼠标左键,我们需要等待它被释放。 (目标是只有一个代码流,而不必在可能已经被另一个代码占用的多个位置之间分割)

我是这样实现的:

public void WaitForMouseUp()
{
    while( (Control.MouseButtons&MouseButtons.Left)!=0 )
        Application.DoEvents();
}

有用,
您可以在例如Control.Enter事件的事件处理程序中使用它时,
并且如果控件是通过鼠标输入的,则此功能将一直阻塞,直到释放鼠标按钮为止。

我只担心一件事:
我在那里使用Application.DoEvents() ,我想知道是否还有另一种方法代替使用Application.DoEvents() (Application.DoEvents();有可能重新输入的缺点,因此,因此,我尝试尽可能地减少使用它)

任何人都可以代替Application.DoEvents()部分有什么想法?

这是完成您要问的一种很棒的方法。 使用Microsoft的Reactive Extensions使一行代码可以完成您想要的所有事情。

响应式扩展提供了大量可用于事件的运算符。

因此,首先是一些与正常控制事件直接相关的基本可观察变量:

        var mouseEnters =
            Observable
                .FromEventPattern(
                    h => button1.MouseEnter += h,
                    h => button1.MouseEnter -= h);

        var mouseLeaves =
            Observable
                .FromEventPattern(
                    h => button1.MouseLeave += h,
                    h => button1.MouseLeave -= h);

        var mouseUps =
            Observable
                .FromEventPattern<MouseEventHandler, MouseEventArgs>(
                    h => button1.MouseUp += h,
                    h => button1.MouseUp -= h);

现在,我们需要一个查询,该查询仅在鼠标向上移动时才触发一次,但button1是鼠标已经进入button1 ,但仅在其离开之前触发。

        var query =
            mouseEnters
                .Select(me => mouseUps.Take(1).TakeUntil(mouseLeaves))
                .Switch();

现在订阅该事件即可处理该事件:

        var subscription =
            query
                .Subscribe(ep =>
                {
                    /*
                        this code runs for the first mouse up only
                        after each mouse enter on `button1`
                        unless the mouse leaves `button1`
                    */
                });

现在因为取消订阅非常简单,因为IDisposablesubscription类型。 因此,您只需调用subscription.Dispose();

只需NuGet“ Rx-WinForms”即可获取项目的信息。

实际上@Kai Brummund的建议是我对Force loop等待事件的 回答的变体。 从那里为MouseUp调整代码很简单

public static class Utils
{
    public static Task WhenMouseUp(this Control control)
    {
        var tcs = new TaskCompletionSource<object>();
        MouseEventHandler onMouseUp = null;
        onMouseUp = (sender, e) =>
        {
            control.MouseUp -= onMouseUp;
            tcs.TrySetResult(null);
        };
        control.MouseUp += onMouseUp;
        return tcs.Task;
    }
}

用法是

Control c = ...;
await c.WhenMouseUp();

相同的技术可以用于任何事件。

如果您不想在单个方法中编写流,则可以使用TaskCompletionSource使其处于等待状态。

您的流程:

await MouseUp();

...

private Task MouseUp() {
  _tcs = new TaskCompletionSource();
  return _tcs.Task;
}

public ... OnMouseUpEvent() {
  _tcs?.SetResult(true);
}

对不起,Pseudo代码,一旦我得到手机以外的东西,它将更新它。

OT:评论员:跳出框框思考!

我需要一个小的功能,它将等待鼠标左键被释放。

不,你不会。 WinForms GUI编程是事件驱动的,异步的。 您应该使用MouseUp事件来检测鼠标按钮的释放。 这确实意味着您需要使用基于状态的异步技术而不是您渴望的同步模型来实现逻辑。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM