使用 Observable / Reactive Extensions 检测鼠标移动开始和停止?
Detecting mouse movement starting and stopping with an Observable / Reactive Extensions?
让我开始:
- 我对 Rx 完全陌生
- 我没有使用 C#/Linq
- 我是 experimenting/learning,所以没有 应用 这个问题
我已经阅读了一些介绍性内容,包括 Matthew Podwysocki 的 Introduction to the Reactive Framework。
所以我从他的一个示例开始,并编写了一些 mouse-drag/line-drawing 代码,如下所示:
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 }));
现在让我们为您的 canvas 定义一个可观察的颜色。请注意,您实际上并不需要 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
.
时设置您的 canvas 颜色
让我开始:
- 我对 Rx 完全陌生
- 我没有使用 C#/Linq
- 我是 experimenting/learning,所以没有 应用 这个问题
我已经阅读了一些介绍性内容,包括 Matthew Podwysocki 的 Introduction to the Reactive Framework。
所以我从他的一个示例开始,并编写了一些 mouse-drag/line-drawing 代码,如下所示:
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 }));
现在让我们为您的 canvas 定义一个可观察的颜色。请注意,您实际上并不需要 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
.