在RX中组合多个事件

时间:2010-03-11 12:06:42

标签: silverlight system.reactive

我在Silverlight应用程序中启用了2个启用了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 个答案:

答案 0 :(得分:2)

我相信我已经解决了自己的问题。

而不是多次订阅我为此而去。

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

它似乎做了我想做的事,但我愿意接受进一步的建议/改进。

答案 1 :(得分:2)

我遇到了这个答案,并认为它没有意义:

    leftHold.Zip(rightHold, (a,b) => true)
        .TakeUntil(leftRelease.Amb(rightRelease))
        .Subscribe(_ => TextOutput.Text =
            (Convert.ToInt32(TextOutput.Text) + 1).ToString());
  • Zip将事件配对 要求我释放左边和 在再次举行之前的权利。 如果我发布权并持有它 再次,这种观察不会发射 试。
  • 我也会认为这个举行 事件只发射一次,所以那里 不应该是任何需要 TakeUntil致电。
  • 我也不知道这个答案会怎样 refire - 似乎只有一个 值。

这是另一种选择:

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

我知道这个问题已经有一年了,但我很想知道我是否错过了某些内容,或者这个答案是否有效。