I am trying to handle a drag & drop interaction, which involves mouse down, mouse move, and mouse up.
Here is a simplified repro of my solution that:
- on mouse down, creates an ellipse and adds it to a canvas
- on mouse move, repositions the ellipse to follow the mouse
on mouse up, changes the colour of the canvas so that it's obvious which one you're dragging.
var mouseDown = Observable.FromEvent<MouseButtonEventArgs>(canvas, "MouseLeftButtonDown"); var mouseUp = Observable.FromEvent<MouseButtonEventArgs>(canvas, "MouseLeftButtonUp"); var mouseMove = Observable.FromEvent<MouseEventArgs>(canvas, "MouseMove"); Ellipse ellipse = null; var q = from start in mouseDown.Do(x => { // handle mousedown by creating a red ellipse, // adding it to the canvas at the right position ellipse = new Ellipse() { Width = 10, Height = 10, Fill = Brushes.Red }; Point position = x.EventArgs.GetPosition(canvas); Canvas.SetLeft(ellipse, position.X); Canvas.SetTop(ellipse, position.Y); canvas.Children.Add(ellipse); }) from delta in mouseMove.Until(mouseUp.Do(x => { // handle mouse up by making the ellipse green ellipse.Fill = Brushes.Green; })) select delta; q.Subscribe(x => { // handle mouse move by repositioning ellipse Point position = x.EventArgs.GetPosition(canvas); Canvas.SetLeft(ellipse, position.X); Canvas.SetTop(ellipse, position.Y); });
the XAML is simply
<Canvas x:Name="canvas"/>
There's a few things I don't like about this code, and I need help refactoring it :)
First of all: the mousedown and mouseup callbacks are specified as side effects. If two subscriptions are made to q
, they will happen twice.
Second, the mouseup callback is specified before the mousemove callback. This makes it a bit hard to read.
Thirdly, the reference to the ellipse seems to be in a silly place. If there's two subscriptions, that variable reference will get overwritten quite quickly. I'm sure that there should be some way we can leverage the let
keyword to introduce a variable to the linq expression that will mean the correct ellipse reference is available to both the mouse move and mouse up handlers
How would you write this code?