Rx中的时变值

时间:2011-09-23 19:59:06

标签: c# .net .net-4.0 system.reactive

我有两个可观察者。一个来自Observable.fromEvent(..),其中基础事件是用户检查Winforms复选框。另一个是Observable.Interval(..),我为了做一些IO而订阅了,我想在没有选中复选框的情况下阻止这个observable执行IO。

我可以这样做:

var gui = new GUI();

var booleans = Observable
    .FromEvent<GUI.NewAllowHandler, bool>(
        h => gui.NewAllow += h,
        h => gui.NewAllow -= h)

Observable.Interval(TimeSpan.FromSeconds(10))
          .CombineLatest(booleans, Tuple.Create)
          .Where(t => t.Item2)
          .Select(t => t.Item1)
          .Subscribe(l => DoStuff(l));

但是这有将混合布尔进出流的开销。如果我可以从booleans变量生成一个时变值,那么更好的方法是这样做,它始终具有最后一个事件的值。然后我可以这样做:

var gui = new GUI();

var booleanState = Observable              // typeof(booleanState) == ???
    .FromEvent<GUI.NewAllowHandler, bool>(
        h => gui.NewAllow += h,
        h => gui.NewAllow -= h)
    .TimeValue()                           // hypothetical syntax


Observable.Interval(TimeSpan.FromSeconds(10))
          .Where(_ => booleanState) 
          .Subscribe(l => DoStuff(l));

,这对我来说似乎更接近问题陈述。在Rx中有没有这样的东西,或者还有什么东西可以让这些问题更容易处理?

3 个答案:

答案 0 :(得分:2)

您的时间间隔中的Where语句应该适用于正常范围的普通bool:

var booleans = Observable
    .FromEvent<GUI.NewAllowHandler, bool>(
        h => gui.NewAllow += h,
        h => gui.NewAllow -= h)

var isBoxChecked = false;
booleans.Subscribe(t => isBoxChecked = t);

Observable.Interval(TimeSpan.FromSeconds(10))
    .Where(_ => isBoxChecked)
    .Subscribe(l => DoStuff(l))

编辑:根据您的评论,另一种方式:

intervals = Observable.Interval(TimeSpan.FromSeconds(10));

booleans
    .Where(t => t)
    .SelectMany(_ => intervals.TakeUntil(booleans))
    .Subscribe(l => DoStuff(l))

答案 1 :(得分:1)

您需要将复选框选中状态建模为行为而不是事件流(因为行为始终具有值,并且此值会在一段时间内发生变化 - 这与复选框选中状态相符)。所以你可以这样做:

var booleans = new BehaviorSubject<bool>(chk.Checked)
var chkEvents = ... //generate boolean observable from checkbox check event
chkEvents.Subscribe(booleans);

Observable.Interval(TimeSpan.FromSeconds(10))
 .Where(i => booleans.First())
 .Subscribe(i => DoIO());

答案 2 :(得分:1)

我打算给你两个解决方案。第一个是一个非常简单,有希望显而易见的只使用一个可观察的。第二个是使用两个可观察量。

由于您只想在选中此框时允许IO,因此这是最简单的方法:

Observable
    .Interval(TimeSpan.FromSeconds(10))
    .Where(_ => gui.IsChecked)
    .Subscribe(l => DoStuff(l));

根本不需要其他可观察物。

但如果你真的需要使用它,那么Switch()扩展方法是你最好的选择。试试这个:

booleans
    .Select(b => b == true
        ? Observable.Interval(TimeSpan.FromSeconds(10)) 
        : Observable.Empty<long>())
    .Switch()
    .Subscribe(l => DoStuff(l));

它很干净,如果没有勾选复选框,有助于显示空白时段。

我希望这会有所帮助。