事件限制/排队 - 反应性扩展?

时间:2012-06-15 16:19:24

标签: c# .net system.reactive silverlight-5.0

我希望在我的一个视图模型中实现一些限制行为。这是一个Silverlight应用程序,但我认为这不是特别重要。

考虑一个具有三个属性的类:

  • Property1
  • Property2
  • Property3

每当更新其中一个属性时,都需要刷新。

private void Refresh()
{
    //Call out to the server, do something when it comes back
}

我的目标如下:

  • 如果正在进行刷新,我们理想情况下应取消对服务器的调用,并发出新请求
  • 如果属性发生变化,我们应该留出一些小的时间窗口(可能是0.1秒),等待其他更改。这样,如果快速更改多个属性(例如,以编程方式),我们不会通过请求向服务器发送垃圾邮件。 0.1秒窗口可以在每次更改时重置,但不是必需的。

如果重要,我正在使用ChannelFactory实现服务器调用。

我可以用什么样的模式来实现这个目标?这是反应性扩展可以帮助我吗?

修改

将保罗的回答标记为正确。虽然ReactiveUI目前不支持silverlight5,但它清楚地概述了使用Rx解决问题的方法/组成步骤。

1 个答案:

答案 0 :(得分:6)

以下是使用ReactiveUI执行此操作的方法:

IObservable<TheData> FetchNewData() 
{
    // TODO: Implement me
}

this.WhenAny(x => x.Property1, x => x.Property2, x => x.Property3, (x,y,z) => Unit.Default)
    .Throttle(TimeSpan.FromMilliseconds(200), RxApp.DeferredScheduler)
    .Select(x => FetchNewData())
    .Switch()    // We only care about the req corresp. to latest values of Prop1-3
    .ToProperty(this, x => x.Data);

更新:以下是如何确保一次只有一个正在运行,但需要注意的是,您可能会得到无序结果。

this.WhenAny(x => x.Property1, x => x.Property2, x => x.Property3, (x,y,z) => Unit.Default)
    .Throttle(TimeSpan.FromMilliseconds(200), RxApp.DeferredScheduler)
    .Select(_ => Observable.Defer(() => FetchNewData()))
    .Merge(1)
    .ToProperty(this, x => x.Data);

您描述的行为实际上可能并不理想,因为如果属性不断变化,您最终将会发出一系列旧请求 - 如果您创建类似“BufferingSwitch()”的内容,您可以对此进行优化“在确定没有变化之前没有返回结果的运算符 - 实际上写起来很酷。

故事的道德,Async Is Complicated™:)