通过一个可观察/响应扩展来检测鼠标移动的开始和停止

本文关键字:移动 鼠标 检测 开始 扩展 响应 一个 观察 | 更新日期: 2023-09-27 18:07:24

让我从:

开始
  1. 我对Rx完全陌生
  2. 我已经不再使用c#/Linq
  3. 我正在试验/学习,所以没有应用程序使用来解决这个问题

我读了一些介绍性的内容,包括Matthew Podwysocki写的《响应式框架简介》。

所以我从他的一个例子开始,写了一些鼠标拖动/绘图代码,像这样:
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的背景色设置为绿色
  • 当鼠标不移动时,我将背景色设置为红色

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

这可能吗?

通过一个可观察/响应扩展来检测鼠标移动的开始和停止

我认为这里的关键是鼠标何时不移动?当它空闲了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的评论,我对更新后的解决方案更满意了。

首先,这里有一个问题:

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可观察对象,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);

你可以设置Subscribecolors,并设置你的画布颜色,每次它发出一个Color