【问题标题】:Detecting mouse movement starting and stopping with an Observable / Reactive Extensions?使用 Observable / Reactive Extensions 检测鼠标移动的开始和停止?
【发布时间】:2015-08-12 12:08:29
【问题描述】:

让我开始:

  1. 我对 Rx 完全陌生
  2. 我没有练习 C#/Linq
  3. 我正在试验/学习,所以这个问题没有应用程序使用

我已经阅读了一些介绍性内容,包括 Matthew PodwysockiIntroduction to the Reactive Framework

所以我从他的一个示例开始,并编写了一些 鼠标拖动/画线代码,如下所示:

var leftMouseDown = Observable.FromEventPattern<MouseEventArgs>(mainCanvas, "MouseLeftButtonDown");
var leftMouseUp = Observable.FromEventPattern<MouseButtonEventArgs>(mainCanvas, "MouseLeftButtonUp");
var mouseMove = Observable.FromEventPattern<MouseEventArgs>(mainCanvas, "MouseMove");

var mouseMoves = from mm in mouseMove
                 let location = mm.EventArgs.GetPosition(mainCanvas)
                 select new { location.X, location.Y };

var mouseDiffs = mouseMoves.Skip(1).Zip(mouseMoves, (l, r) => new { X1 = l.X, Y1 = l.Y, X2 = r.X, Y2 = r.Y });

var mouseDrag = from _ in leftMouseDown
                from md in mouseDiffs.TakeUntil(leftMouseUp)
                select md;

var mouseSub = mouseDrag.Subscribe(item =>
{
     var line = new Line
     {
         Stroke = Brushes.LightSteelBlue,
         X1 = item.X1,
         X2 = item.X2,
         Y1 = item.Y1,
         Y2 = item.Y2,
         StrokeThickness = 5
     };
     mainCanvas.Children.Add(line);
 });

我的问题

基于该示例,我想尝试对鼠标移动做出反应,例如:

  • 鼠标移动时,我将someCanvas的背景色设置为绿色
  • 当鼠标不动时,我将背景颜色设置为红色

鼠标左键,只涉及鼠标移动。

这可能吗?

【问题讨论】:

标签: c# linq system.reactive


【解决方案1】:

我认为这里的关键是鼠标什么时候不动?当它空闲了 1 秒、10 秒、250 毫秒?以下应该做你想要的。它是bool 类型的可观察对象。当鼠标移动时它产生true,如果鼠标空闲时间超过指定的空闲时间,它产生false

int idleTime = 1000;

var mouseMoving =
    mouseMove
    .Buffer(TimeSpan.FromMilliseconds(idleTime), 1) // Buffer the mouse move events for the duration of the idle time.
    .Select(x => x.Any())                           // Return true if the buffer is not empty, false otherwise.
    .DistinctUntilChanged();                        // Only notify when the mouse moving state changes.

我会第一个告诉你,我怀疑这不是最好的解决方案。缓冲鼠标移动事件似乎是不必要的浪费。我尝试使用Sample 找到解决方案,但无法解决。?

感谢 Jerry 的评论,我对更新后的解决方案感到更加满意。

【讨论】:

  • 我认为,如果您还将容量限制 1 传递给缓冲区,那么您将获得响应更快的结果。一旦缓冲区中有任何内容,我们就知道您应该发出 false 并重新启动限时缓冲区。
  • @Jerry - 看看那个。我完全错过了需要持续时间和窗口大小的过载这一事实。谢谢。
  • @JasonBoyd 谢谢。我也不知道这是否是最好的解决方案,但给了我考虑的信息并帮助我学习(因此赞成)。干杯。
【解决方案2】:

首先这里有个问题:

var mouseDiffs = mouseMoves.Skip(1)
    .Zip(mouseMoves, (l, r) => new { X1 = l.X, Y1 = l.Y, X2 = r.X, Y2 = r.Y });

当观察者订阅mouseDiffs 时,两个订阅mouseMoves。您应该改用Publish 以确保每次订阅mouseDiffs 只订阅一次mouseMoves

var mouseDiffs = mouseMoves.Publish(obs => obs.Skip(1)
    .Zip(obs, (l, r) => new { X1 = l.X, Y1 = l.Y, X2 = r.X, Y2 = r.Y }));

现在让我们为您的画布定义一个可观察的颜色。请注意,您实际上并不需要您的 mouseDiffs observable - mouseMove 可以正常工作。

var colors = mouseMove
    .Select(_ => Observable.Concat(
        Observable.Return(true),
        Observable.Return(false).Delay(TimeSpan.FromSeconds(1))))
    .Switch()
    .StartWith(false)
    .DistinctUntilChanged()
    .Select(isActive => isActive ? Color.Green : Color.Red);

您可以将Subscribe 设置为colors,并在每次发出Color 时设置您的画布颜色。

【讨论】:

  • 感谢您提供有关Publish 的信息...我从您的答案中尝试了colors 可观察到的值,但它从未发出红色。 (我认为)为了获得新的鼠标移动(以及对 mouseDiffs 的更新),xy 必须不同于之前的 x / y 值?
  • @GavinHope 哦,我明白了 - 除非鼠标移动,否则您不会收到任何鼠标移动事件!我将更新答案以改用超时行为。
  • 在这种情况下,使用_(下划线)是不是很简单?
  • @GavinHope 下划线是表示未使用 lambda 参数的约定。我忽略了传递给 lambda 的 MouseEventArgs
猜你喜欢
  • 1970-01-01
  • 2015-11-17
  • 2015-07-06
  • 2012-07-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多