如何随时间动态延迟可观察的
How to dynamically delay observable over time
我目前有一个功能,用户 Timer()
可以立即触发一个 observable,然后每隔 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
是你的朋友(在 this 页面上讨论得很好)。
对于越来越频繁的值,将 .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();
对我来说,这更容易阅读,查询的意图也很清楚。
只是留下了MouseDowns
、MouseUps
、Generate
的定义。它们是:
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)));
既然这些都被分开了,就更容易确认每一个都是正确的,希望整个代码都是正确的。
我目前有一个功能,用户 Timer()
可以立即触发一个 observable,然后每隔 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
是你的朋友(在 this 页面上讨论得很好)。
对于越来越频繁的值,将 .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();
对我来说,这更容易阅读,查询的意图也很清楚。
只是留下了MouseDowns
、MouseUps
、Generate
的定义。它们是:
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)));
既然这些都被分开了,就更容易确认每一个都是正确的,希望整个代码都是正确的。