开发者

Combining Multiple Events in RX

I have 2 touch enabled Canvas' in a Silverlight App. What I need to do is when a person Holds (presses and keeps pressing) both canvases at the same time increment a value on the screen once. This should happen for every "double" hold. I can do that fine using normal events but tried writing the same thing using RX and I am getting stuck.

Currently my code looks identical to the separate events approach (using global variables and global method) but I think there must be a better way to compose this. Can anyone suggest a better approach?

        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();
        });

And the very basic DoCheck function looks like this....

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

Hopefully you can see what I am trying to do. Each canvas has a hold and release event so 开发者_如何学编程when HoldLeft and HoldRight are both held do something until either HoldRight or HoldLeft are is released.

Any help would be appreciated.


I believe I have solved my own problem.

Rather than the multiple subscribes I went for this.

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

It appears to do what I want but I am open to further suggestions/improvements.


I came across this answer and thought that it didn't make sense:

    leftHold.Zip(rightHold, (a,b) => true)
        .TakeUntil(leftRelease.Amb(rightRelease))
        .Subscribe(_ => TextOutput.Text =
            (Convert.ToInt32(TextOutput.Text) + 1).ToString());
  • Zip pairs up events so would require that I release the left and the right before holding them again. If I released right and the held it again this observable wouldn't fire again.
  • I also would think that the hold events only fire once, so there shouldn't be any need for a TakeUntil call.
  • Also I don't see how this answer will refire - it seems to get only one value.

Here's an alternative:

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);

I know this question is a year old, but I would love to know if I've missed something or if this answer works.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜