Rx 最大的特点就是可以对事件进行组合形成一个新的事件。比如下面的这个拖拽。我们对于拖拽的定义是:当鼠标按下时开始DragDrop,当鼠标移动时移动图形,最后当鼠标放开时停止DragDrop。
我定义了一些图形放在ToolBar里,点击ToolBar里的图形将在Canvas里创建新的图形,在Canvas里可以拖拽它们移动。
using System; using System.Reactive.Linq; using System.Threading; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Input; namespace RxDragDownSample { /// <summary> /// MainWindow.xaml 的交互逻辑 /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void btnCircular_Click_1(object sender, RoutedEventArgs e) { AddShape<Shapes.Circular>(); } private void btnSquare_Click_1(object sender, RoutedEventArgs e) { AddShape<Shapes.Square>(); } private void btnTriangle_Click_1(object sender, RoutedEventArgs e) { AddShape<Shapes.Triangle>(); } private void AddShape<T>() where T : new() { var shape = (new T()) as UserControl; myCanvas.Children.Add(shape); Canvas.SetLeft(shape, 10); Canvas.SetTop(shape, 10); var minX = 0; var maxX = myCanvas.ActualWidth - 30; var minY = 0; var maxY = myCanvas.ActualHeight - 30; // 鼠标在Shape上按下,开始DragDrop var mouseDown = from evt in Observable.FromEventPattern<MouseButtonEventArgs>(shape, "MouseLeftButtonDown") select evt.EventArgs.GetPosition(this); // 鼠标移动,取得坐标 var mouseMove = from evt in Observable.FromEventPattern<MouseEventArgs>(this, "MouseMove") select evt.EventArgs.GetPosition(this); // 鼠标放开,终止DragDrop var mouseUp = from evt in Observable.FromEventPattern<MouseButtonEventArgs>(this, "MouseLeftButtonUp") select evt.EventArgs.GetPosition(this); // 当鼠标移出Window,终止DragDrop var mouseLeave = from evt in Observable.FromEventPattern<MouseEventArgs>(this, "MouseLeave") select evt; var mouseMoves = mouseMove.Skip(1).Zip(mouseMove, (prev, cur) => new { X = prev.X - cur.X, Y = prev.Y - cur.Y }); var dragDrop = mouseDown.SelectMany(mouseMoves.TakeUntil(mouseUp).TakeUntil(mouseLeave)); dragDrop.ObserveOn(SynchronizationContext.Current).Subscribe(p => { var x = Math.Min(Math.Max(Canvas.GetLeft(shape) + p.X, minX), maxX); var y = Math.Min(Math.Max(Canvas.GetTop(shape) + p.Y, minY), maxY); Canvas.SetLeft(shape, x); Canvas.SetTop(shape, y); this.lblPosition.Content = "{x:" + x.ToString() + ",y:" + y.ToString() + "}"; }); } } }
利用 Observable.FromEventPattern<T> 我们将"MouseLeftButtonDown", "MouseMove", "MouseLeftButtonUp", "MouseLeave" 事件先转化成 IObervable<T> 的Rx对象。
mouseMoves则是对连续的 mouseMove 进行了Zip 获得鼠标位移(offset)
var mouseMoves = mouseMove.Skip(1).Zip(mouseMove, (prev, cur) => new { X = prev.X - cur.X, Y = prev.Y - cur.Y });
如图:
最后 DragDrop 事件:
var dragDrop = mouseDown.SelectMany(mouseMoves.TakeUntil(mouseUp).TakeUntil(mouseLeave));