Rx-跟踪鼠标平移操作



我正在实现一个点击和拖动类型的操作,用于在图形应用程序中平移相机。

我想跟踪我们是否在另一个流中平移,这可以通过其他操作进行检查以进行过滤(例如,如果我们正在平移,我们不应该允许选择橡皮筋(。

代码看起来像这样:

MouseClicked
.Where(startClick => startClick.Action == MouseAction.LeftDown)
.SelectMany(_ =>
MouseMoved
.Select(endMove => (_.startClick, endMove))
.TakeUntil(MouseReleased))
.Subscribe(_ => PanCamera(_.startClick, _.endMove));

我的解决方案是添加以下两行代码

MouseClicked
.Where(startClick => startClick.Action == MouseAction.LeftDown)
.Do(_ => _isPanning.OnNext(true))  // Add this
.SelectMany(_ =>
MouseMoved
.Select(endMove => (_.startClick, endMove))
.TakeUntil(MouseReleased)
.Finally(() => _isPanning.OnNext(false))   // Add this
)
.Subscribe(_ => PanCamera(_.startClick, _.endMove));

其中,_isPanningSubject。这很好,但我想知道是否有更好的方法,而不必使用Subject.

您可以将平移状态折叠为具有多个订阅者的单个可观察状态,而不是使用Subject。例如:

public IDisposable PanningBehaviour()
{
var observable = MouseClicked
.Where(startClick => startClick.Action == MouseAction.LeftDown)
.SelectMany(start =>
MouseMoved
.Select(current => (Start: start.Position, Current: current.Position, Panning: PanningState.Panning))
.TakeUntil(MouseReleased)
.Concat(Observable.Return((Start: Point.Empty, Current: Point.Empty, Panning: PanningState.NotPanning))))
.Publish();
var cameraSubscription = observable
.Where(tuple => tuple.Panning == PanningState.Panning)
.Subscribe(tuple => PanCamera(tuple.Start, tuple.Current));
var notPanningSubscription = observable
.Select(tuple => tuple.Panning == PanningState.NotPanning)
.Subscribe(allowOperations => { /* Allow / disallow actions */ });
return new CompositeDisposable(
notPanningSubscription,
cameraSubscription,
observable.Connect()
);
}

/* Allow / disallow actions */中,你可以放任何你喜欢的东西。在MVVM应用程序中,这种方法与允许外部代码控制其"CanExecute"状态的ICommand实现配合得特别好。

FWIW,我的MVx.Observable包具有Observable.Command,它可以直接订阅"notPanning"状态,如下所示:

private MVx.Observable.Command _allowSelection = new MVx.Observable.Command();
public IDisposable PanningBehaviour()
{
var observable = MouseClicked
.Where(startClick => startClick.Action == MouseAction.LeftDown)
.SelectMany(start =>
MouseMoved
.Select(current => (Start: start.Position, Current: current.Position, Panning: PanningState.Panning))
.TakeUntil(MouseReleased)
.Concat(Observable.Return((Start: Point.Empty, Current: Point.Empty, Panning: PanningState.NotPanning))))
.Publish();
var cameraSubscription = observable
.Where(tuple => tuple.Panning == PanningState.Panning)
.Subscribe(tuple => PanCamera(tuple.Start, tuple.Current));
var notPanningSubscription = observable
.Select(tuple => tuple.Panning == PanningState.NotPanning)
.Subscribe(_allowSelection);
return new CompositeDisposable(
notPanningSubscription,
cameraSubscription,
observable.Connect()
);
}
public ICommand AllowSelection => _allowSelection;

希望能有所帮助。

最新更新