public ImageQuadranglePicker() { Canvas.KeyDown += Canvas_KeyDown; var lostFocus = Observable.FromEventPattern <EventArgs>(Canvas, "LostFocus").Select(e => e.EventArgs); var mouseUp = Observable.FromEventPattern <MouseEventArgs>(Canvas, "MouseUp").Select(e => e.EventArgs); var mouseDown = Observable.FromEventPattern <MouseEventArgs>(Canvas, "MouseDown").Select(e => e.EventArgs); var mouseMove = Observable.FromEventPattern <MouseEventArgs>(Canvas, "MouseMove").Select(e => e.EventArgs); var mouseLeftButtonUp = mouseUp.Where(evt => evt.Button == MouseButtons.Left); var mouseLeftButtonDown = mouseDown.Where(evt => evt.Button == MouseButtons.Left); var mouseRightButtonDown = mouseDown.Where(evt => evt.Button == MouseButtons.Right && !MouseButtons.HasFlag(MouseButtons.Left)); var mouseDrag = mouseLeftButtonDown.SelectMany(downEvt => { var image = Image; var downPoint = ImagePoint(downEvt.X, downEvt.Y, image); var cornerIndex = CornerIndex(downPoint); commandExecutor.BeginCompositeCommand(); commandExecutor.Execute(() => { }, UpdateQuadrangle); UpdatePoint(cornerIndex, quadrangle[cornerIndex]); return(mouseMove .TakeUntil(mouseLeftButtonUp.Merge(lostFocus)) .Select(evt => ImagePoint(evt.X, evt.Y, image)) .Do(point => { quadrangle[cornerIndex] = point; UpdateQuadrangle(); }) .TakeLast(1) .Do(point => { UpdatePoint(cornerIndex, point); commandExecutor.Execute(UpdateQuadrangle, () => { }); }) .Finally(commandExecutor.EndCompositeCommand)); }); mouseDrag.Subscribe(); mouseRightButtonDown.Subscribe(evt => { var image = Image; if (image != null) { InitializeQuadrangle( new Point2f(0, 0), new Point2f(0, image.Height), new Point2f(image.Width, image.Height), new Point2f(image.Width, 0)); } else { InitializeQuadrangle( new Point2f(-1, -1), new Point2f(-1, 1), new Point2f(1, 1), new Point2f(1, -1)); } }); }