Объединение нескольких событий в RX - PullRequest
1 голос
/ 11 марта 2010

У меня в приложении Silverlight есть приложение Canvas с поддержкой двух касаний. Что мне нужно сделать, так это когда человек удерживает (нажимает и продолжает нажимать) оба полотна одновременно, увеличивая значение на экране один раз. Это должно происходить для каждого «двойного» удержания. Я могу сделать это нормально, используя обычные события, но попытался написать то же самое, используя RX, и я застреваю.

В настоящее время мой код выглядит идентично подходу отдельных событий (с использованием глобальных переменных и глобального метода), но я думаю, что должен быть лучший способ составить это. Кто-нибудь может предложить лучший подход?

        var leftHold = Observable.FromEvent<TCanvas.HoldHandler, GestureHoldEventArgs>(
                h => new TCanvas.HoldHandler(h),
                h => HoldLeft.Hold += h,
                h => HoldLeft.Hold += h
            );

        var rightHold = Observable.FromEvent<TCanvas.HoldHandler, GestureHoldEventArgs>(
                h => new TCanvas.HoldHandler(h),
                h => HoldRight.Hold += h,
                h => HoldRight.Hold += h
            );

        var rightRelease = Observable.FromEvent<TCanvas.ReleaseHandler, EventArgs>(
                h => new TCanvas.ReleaseHandler(e => { }),
                h => HoldRight.Release += h,
                h => HoldRight.Release += h
            );


        var leftRelease = Observable.FromEvent<TCanvas.ReleaseHandler, EventArgs>(
                h => new TCanvas.ReleaseHandler(e => { }),
                h => HoldLeft.Release += h,
                h => HoldLeft.Release += h
            );

        leftHold.Subscribe(e =>
        {
            _leftHeld = true;
            DoCheck();
        });

        rightHold.Subscribe(e =>
            {
                _rightHeld = true;
                DoCheck();
            });

        rightRelease.Subscribe(e =>
        {
            _rightHeld = false;
            DoCheck();
        });


        leftRelease.Subscribe(e =>
        {
            _leftHeld = false;
            DoCheck();
        });

И очень простая функция DoCheck выглядит следующим образом ...

    private void DoCheck()
    {
        if (_rightHeld && _leftHeld)
        {
            MyTextBox.Text = (Convert.ToInt32(MyTextBox.Text) + 1).ToString() ;
        }
    }

Надеюсь, вы увидите, что я пытаюсь сделать. У каждого холста есть события hold и release, поэтому, когда HoldLeft и HoldRight оба удерживаются, делают что-то до тех пор, пока не отпустят HoldRight или HoldLeft.

Любая помощь будет оценена.

Ответы [ 2 ]

2 голосов
/ 29 марта 2011

Я наткнулся на этот ответ и подумал, что он не имеет смысла:

    leftHold.Zip(rightHold, (a,b) => true)
        .TakeUntil(leftRelease.Amb(rightRelease))
        .Subscribe(_ => TextOutput.Text =
            (Convert.ToInt32(TextOutput.Text) + 1).ToString());
  • Zip объединяет события в пары, поэтому мне потребуется освободить левую и правую части перед их удержаниемснова.Если бы я отпустил право и снова удержал его, эта наблюдаемая не сработала бы снова.
  • Я бы также подумал, что события удержания срабатывают только один раз, поэтому в вызове TakeUntil не должно быть необходимости.
  • Кроме того, я не вижу, как этот ответ будет повторяться - похоже, он получает только одно значение.

Вот альтернатива:

var left = leftHold.Select(x => true).Merge(leftRelease.Select(x => false));
var right = rightHold.Select(x => true).Merge(rightRelease.Select(x => false));

var bothHold =
    left.CombineLatest(right, (l, r) => l && r)
        .Where(lr => lr == true)
        .Select(lr => (Convert.ToInt32(MyTextBox.Text) + 1).ToString());

bothHold.Subscribe(t => MyTextBox.Text = t);

Я знаюэтому вопросу год, но мне бы хотелось узнать, пропустил ли я что-то или этот ответ работает.

2 голосов
/ 11 марта 2010

Мне кажется, я решил свою проблему.

Вместо нескольких подписок я пошел на это.

        leftHold.Zip(rightHold, (a,b) => true)
            .TakeUntil(leftRelease.Amb(rightRelease))
            .Subscribe(_ => TextOutput.Text = (Convert.ToInt32(TextOutput.Text) + 1).ToString());

Кажется, я делаю то, что хочу, но я открыт для дальнейших предложений / улучшений.

...