Reputation: 2193
Let me start with:
I've read some introductory content, including this Introduction to the Reactive Framework by Matthew Podwysocki.
So I've started out with one of his examples and written some mouse-drag/line-drawing code like this:
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);
});
My question
Based on playing with that example, I'd like to try reacting to mouse movement, such that:
someCanvas
to greenLeft mouse button is not involved, just the mouse movement.
Is that possible?
Upvotes: 1
Views: 590
Reputation: 79461
First, there is a problem here:
var mouseDiffs = mouseMoves.Skip(1)
.Zip(mouseMoves, (l, r) => new { X1 = l.X, Y1 = l.Y, X2 = r.X, Y2 = r.Y });
When an observer subscribes to mouseDiffs
, two subscriptions are made to mouseMoves
. You should use Publish
instead to ensure only a single subscription to mouseMoves
per subscription to mouseDiffs
:
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 }));
Now let's define an observable of colors for your canvas. Note you don't actually need your mouseDiffs
observable - mouseMove
will work fine for this.
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);
You can Subscribe
to colors
and set your canvas color each time it emits a Color
.
Upvotes: 1
Reputation: 7029
I think the key here is when is the mouse not moving? When it has been idle for 1 second, 10 seconds, 250 milliseconds? The following should do what you want. It is an observable of type bool
. It yields true
when the mouse is moving and false
if the mouse is idle longer than the specified idle time.
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.
I will be the first to tell you that I suspect this is not the best solution. It seems needlessly wasteful to buffer mouse move events. I tried to find a solution using ?Sample
but I was unable to make that work.
I am much more comfortable with the updated solution thanks to Jerry's comment.
Upvotes: 5