如何动态延迟可观察的随时间变化



我目前有一个功能,用户Timer()立即触发一个可观察量,然后每x毫秒触发一次。

HoldPayloads = Observable.Merge(
EnumeratedSymbolKeys.Select(
o => Observable.FromEventPattern<MouseButtonEventHandler, MouseButtonEventArgs>(
h => o.PreviewMouseLeftButtonDown += h,
h => o.PreviewMouseLeftButtonDown -= h)
.Select(_ => Observable.Timer(DateTimeOffset.Now, TimeSpan.FromMilliseconds(o.Frequency))
.TakeUntil(Observable.FromEventPattern<MouseButtonEventHandler, MouseButtonEventArgs>(
h => o.PreviewMouseLeftButtonUp += h,
h => o.PreviewMouseLeftButtonUp -= h)))
.Switch()
.Select(_ => o.Payload)));

我想要的是 当单击按钮时立即观察到的触发,然后在初始较长的延迟后开始以更快的间隔或减少的间隔重复,直到限制,如下所示:

--x------x--x--x--x--x--x-->

--x------x----x---x--x-x-x->

我试图将Delay()Scan()结合使用来生成指数级较低的值来延迟,但无法使其正常工作。我走在正确的轨道上吗?有什么更好的方法来做这样的事情吗?

使用Shlomo的答案修改了代码:

HoldPayloads = Observable.Merge(
EnumeratedSymbolKeys.Select(
o => Observable.FromEventPattern<MouseButtonEventHandler, MouseButtonEventArgs>(
h => o.PreviewMouseLeftButtonDown += h,
h => o.PreviewMouseLeftButtonDown -= h)
.Select(_ => Observable.Generate(
1,
q => true,
i => i+1,
i => i,
i => i==1
? TimeSpan.FromMilliseconds(0)
: i > 10
? TimeSpan.FromMilliseconds(50)
: TimeSpan.FromMilliseconds(500/i))
.TakeUntil(Observable.FromEventPattern<MouseButtonEventHandler, MouseButtonEventArgs>(
h => o.PreviewMouseLeftButtonUp += h,
h => o.PreviewMouseLeftButtonUp -= h)))
.Switch()
.Select(_ => o.Payload)));

最终修改了条件,以便第一项是即时的。

Observable.Generate

是你的朋友(在这个页面上讨论得很好(。

对于越来越频繁的值,请将.Select(_ => Observable.Timer(DateTimeOffset.Now, TimeSpan.FromMilliseconds(o.Frequency))替换为如下所示的内容:

Observable.Generate(
1, 
_ => true,
i => i + 1,
i => i,
i => i > 10
? TimeSpan.FromMilliseconds(50)
: TimeSpan.FromMilliseconds(500 / i)
)            

无论您的模式是什么,请将其放入最后一个参数中。Generate就像一个反应式 for 循环,其中包含所有可用的表盘。


编辑

使用上面的代码,Generate的第一项将被延迟。如果要立即执行第一项,则延迟第二项,可以执行以下操作:

Observable.Generate(
1, 
_ => true,
i => i + 1,
i => i,
i => i > 10
? TimeSpan.FromMilliseconds(50)
: TimeSpan.FromMilliseconds(500 / i)
)            
.StartWith(0)

所以原来的.Select(_ => Observable.Timer(DateTimeOffset.Now, TimeSpan.FromMilliseconds(o.Frequency)现在.Select(_ => Observable.Generate(...).StartWith(0))

我只是想添加一个答案来帮助使最终查询更具可读性。我没有以任何方式改变答案,我不希望这个答案被接受甚至投票。我只是想帮助澄清如何理解查询。

我刚刚做了一些替换重构,并将查询更改为:

HoldPayloads =
EnumeratedSymbolKeys
.Select(o =>
MouseDowns(o)
.Select(_ => Generate().TakeUntil(MouseUps(o)))
.Switch()
.Select(_ => o.Payload))
.Merge();

对我来说,这更容易阅读,查询的意图非常明确。

它只留下了MouseDownsMouseUpsGenerate的定义。这些是:

IObservable<Unit> MouseDowns(EnumeratedSymbolKey o) =>
Observable
.FromEventPattern<MouseButtonEventHandler, MouseButtonEventArgs>(
h => o.PreviewMouseLeftButtonDown += h, h => o.PreviewMouseLeftButtonDown -= h)
.Select(EncodingProvider => Unit.Default);
IObservable<Unit> MouseUps(EnumeratedSymbolKey o) =>
Observable
.FromEventPattern<MouseButtonEventHandler, MouseButtonEventArgs>(
h => o.PreviewMouseLeftButtonUp += h, h => o.PreviewMouseLeftButtonUp -= h)
.Select(EncodingProvider => Unit.Default);          
IObservable<int> Generate() =>
Observable
.Generate(1, i => true, i => i + 1, i => i,
i => i == 1
? TimeSpan.FromMilliseconds(0) 
: (i > 10 ? TimeSpan.FromMilliseconds(50) : TimeSpan.FromMilliseconds(500 / i)));

现在这些都分开了,更容易确认每个都是正确的,并希望整个代码是正确的。

相关内容

  • 没有找到相关文章

最新更新