Изменяющиеся во времени значения в Rx - PullRequest
0 голосов
/ 23 сентября 2011

У меня есть две наблюдаемые. Один из них Observable.fromEvent(..), где основным событием является пользователь, устанавливающий флажок Winforms. Другой - Observable.Interval(..), на который я подписываюсь, чтобы выполнить IO, и я бы хотел, чтобы эта наблюдаемая не выполняла 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 ]

2 голосов
/ 24 сентября 2011

Оператор 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 голос
/ 24 сентября 2011

Я собираюсь дать вам два решения. Первый - очень простой и, надо надеяться, очевидный, использующий только одну наблюдаемую. Второй использует обе наблюдаемые.

Поскольку вы хотите разрешить ввод-вывод только при установленном флажке, это самый простой подход:

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

Это довольно чисто и помогает показать, что есть пустые периоды, если флажок не отмечен.

Надеюсь, это поможет.

1 голос
/ 24 сентября 2011

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

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