如何中断现有的IObservable序列?

时间:2016-12-14 14:15:27

标签: c# .net system.reactive

我有

我有一个由触摸事件制作的可观察序列:

 var touchEvents = Observable.Merge(
     Observable.FromEventPattern<RoutedEventArgs>(touchRect, nameof(touchRect.PointerEntered)),
     Observable.FromEventPattern<RoutedEventArgs>(touchRect, nameof(touchRect.PointerExited)),
     Observable.FromEventPattern<RoutedEventArgs>(touchRect, nameof(touchRect.PointerReleased)));

我观察直到满足特定条件:

async void Start()
{
    _scanSlapObservable = touchEvents.Throttle(TimeSpan.FromSeconds(1))
                    .Where(e => countOfPointers == expectedFingers.Length)
                    .Select(e => new Response())
                    .FirstOrDefaultAsync();

    Response response = await _scanSlapObservable;
    if (response != null)
    { 
       //do something
    }
}

我需要什么

当我两次调用Start()时,我想中断现有的_scanSlapObservable,因此它返回null或抛出异常。

如何中断现有的IObservable序列?

1 个答案:

答案 0 :(得分:0)

这是Linqpad友好的解决方案。丑陋,但它确实有效:

async Task Main()
{
    var sc = new ScanClass();
    sc.Start();
    sc.touchEvents.OnNext(Unit.Default);
    sc.touchEvents.OnNext(Unit.Default);
    sc.Start();
    sc.touchEvents.OnNext(Unit.Default);
    sc.touchEvents.OnNext(Unit.Default);
    await Task.Delay(TimeSpan.FromSeconds(1));
}

// Define other methods and classes here
class ScanClass
{
    IObservable<Response> _scanSlapObservable;
    public Subject<Unit> _interrupter = new Subject<Unit>();
    public Subject<Unit> touchEvents = new Subject<Unit>();

    public async Task Start()
    {
        _interrupter.OnNext(Unit.Default);

        _scanSlapObservable = touchEvents
                        .Throttle(TimeSpan.FromSeconds(1))
//                      .Where(e => countOfPointers == expectedFingers.Length)
                        .Select(e => new Response())
                        .TakeUntil(_interrupter)
                        .FirstOrDefaultAsync();

        Response response = await _scanSlapObservable;
        if (response != null)
        {
            //do something
            Console.WriteLine("Do Something");
        }
        else
        {
            Console.WriteLine("Null Response");
        }
    }
}
class Response { }

我认为最好的方法是Switch风格,但这不适用于Task。我认为丑陋的很大一部分是将Task API与Rx混合在一起。这是Rx专用解决方案的样子:

class ScanClass
{
    public Subject<Unit> _starter = new Subject<Unit>();
    public Subject<Unit> touchEvents = new Subject<Unit>();

    public ScanClass()
    {
        _starter.Select(_ => touchEvents
            .Throttle(TimeSpan.FromSeconds(1))
//          .Where(e => countOfPointers == expectedFingers.Length)
            .Select(e => new Response())
        )
        .Switch()
        .Subscribe(r => Console.WriteLine("Do Something."));
    }

public async Task Start()
    {
        _starter.OnNext(Unit.Default);
    }
}

...理想情况下,您会使用某种Start()替换_starterObservable.FromEvent