我正在实现单击并拖动类型的操作,以在图形应用程序中平移相机。
我想跟踪是否在另一个流中平移,可以通过其他操作进行过滤以检查目的(例如,在平移时我们不应该选择橡皮筋)。
代码看起来像这样:
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));
_isPanning
是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应用程序中,此方法特别适合ICommand实现,该实现允许外部代码控制其“ CanExecute”状态。
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;
希望有帮助。