Rx-跟踪鼠标平移操作

问题描述 投票:0回答:1

我正在实现单击并拖动类型的操作,以在图形应用程序中平移相机。

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

代码看起来像这样:

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.

reactive-programming system.reactive
1个回答
0
投票

除了使用主题以外,您还可以将平移状态折叠为一个可观察到的具有多个订阅者的状态。例如:

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;

希望有帮助。

© www.soinside.com 2019 - 2024. All rights reserved.