Ответ - да. Сначала ответьте, затем объясните:
public static class X
{
public static IObservable<T> GatedDebounce<T>(this IObservable<T> source, IObservable<bool> gating)
{
var finalStream = gating
.StartWith(false)
.DistinctUntilChanged()
.Publish(_gating => source.Publish(_source => Observable.Merge(
_source
.Window(_gating.Where(b => b), _ => _gating.Where(b => !b))
.SelectMany(o => o.LastAsync()),
_source
.Window(_gating.Where(b => !b), _ => _gating.Where(b => b))
.Merge()
)));
return finalStream;
}
}
Затем, учитывая IObservable<T>
, представляющий ваши значения, и IObservable<bool>
, представляющий, где перетаскивание начинается и останавливается (истинное значение означает drag-start, и ложное значение drag-end), вы бы назвали это так:
var throttledStream= valueStream.GatedDebounce(gateStream);
Пояснение :
Чтобы лучше это понять, давайте выбросим Publish
вызовы иразбить его на части:
Piece 1,
source
.Window(gating.Where(b => b), _ => gating.Where(b => !b))
.SelectMany(o => o.LastAsync())
Эта Window
функция означает, что вызов означает, что мы запускаем поднабор наблюдаемый (или окно) всякий раз, когда стробирование выдает истину, и завершаемэто окно всякий раз, когда гейтинг выдает false. В этом окне мы выбираем последний элемент, если он существует. Он будет выдан только при закрытии окна.
Piece 2,
source
.Window(gating.Where(b => !b), _ => gating.Where(b => b))
.Merge() //Equivalent to .SelectMany(o => o) if you prefer
Эта функция Window
делает противоположное: запускает окно всякий раз, когда gating генерирует false, и завершает его всякий раз, когда gatingиспускает истину. Из этого окна мы испускаем все, когда оно появляется.
Соедините эти два с Merge
, и вы получите 90% пути к вашему решению. Остальное:
- * * * * * * * * * * * * *
.StartWith(false)
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *1033* 1036 * - это дешевый способ убедиться, что у наших ворот есть t, f, t, f и никогда два одинаковых значения в строке, что может привести к открытию двух одновременных окон. Publish
звонки - это хорошая практика для предотвращения нескольких подписок. Вы можете найти лучшие объяснения этому в некоторых других вопросах и ответах здесь.