Rx 最大的特点就是可以对事件进行组合形成一个新的事件。比如下面的这个拖拽。我们对于拖拽的定义是:当鼠标按下时开始DragDrop,当鼠标移动时移动图形,最后当鼠标放开时停止DragDrop。
利用 Observable.FromEventPattern<T> 我们将"MouseLeftButtonDown", "MouseMove", "MouseLeftButtonUp", "MouseLeave" 事件先转化成 IObervable<T> 的Rx对象。
mouseMoves则是对连续的 mouseMove 进行了Zip 获得鼠标位移(offset)
最后 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));
【源码下载】