2012-06-15 20 views
7

Estoy buscando implementar algún comportamiento de regulación en uno de mis modelos de vista. Es una aplicación Silverlight, sin embargo, no creo que sea particularmente importante.Estrangulamiento/colas de eventos - ¿Extensiones reactivas?

Considérese una clase con tres propiedades:

  • Propiedad1
  • Propiedad2
  • Propiedad3

Cada vez que una de estas propiedades se actualiza, una actualización es necesario.

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

Mis objetivos son los siguientes:

  • Si una actualización está en curso, que idealmente debería cancelar la llamada al servidor, y emitir una nueva solicitud
  • Si se cambia una propiedad, deberíamos dejar una pequeña ventana de tiempo (quizás 0.1 segundos) donde esperamos cambios adicionales. De esta forma, si se cambian rápidamente varias propiedades (por ejemplo, mediante programación), no enviamos spam al servidor con solicitudes. Está bien que se restablezca esa ventana de 0.1 segundos en cada cambio, pero no es obligatorio.

Si es importante, estoy utilizando una implementación de ChannelFactory para la llamada al servidor.

¿Qué tipo de patrones puedo usar para lograr esto? ¿Esto es algo con lo que las extensiones reactivas pueden ayudarme?

Editar:

Marcado respuesta de Pablo como correcta. Si bien ReactiveUI no funciona actualmente en contra de silverlight5, describe claramente los pasos de aproximación/composición para resolver el problema utilizando Rx.

+1

Rx definitivamente apoya esto, ver http://rxwiki.wikidot.com/101samples#toc29 - sobre la cancelación de ella - echar un vistazo a CancellationToken de Tareas –

Respuesta

6

Así es como podría hacer esto con 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); 

Actualización: Así es como para garantizar que sólo hay uno funcionando a la vez, con la advertencia de que es posible salir de la orden resultados.

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

El comportamiento que usted describe, en realidad sería tal vez no sea deseable, ya que si las propiedades cambian constantemente, que va a terminar con una cola de solicitudes para emitir viejos - se puede optimizar este si hizo algo así como una El operador "BufferingSwitch()" que no devolvió sus resultados hasta que estuvo seguro de que no hubo cambios, eso sería genial para escribir.

Moraleja de la historia, asíncrono es complicado ™ :)

+0

Gracias, parece lo que necesito a primera vista. ¿Es esto válido para Silverlight? No puedo encontrar el método de extensión WhenAny para intentar esto. –

+0

@ShaunRowan: Esa extensión es de ReactiveUI (http://www.reactiveui.net). Las versiones anteriores (v2) son compatibles con Silverlight. La versión actual (v3) no. Especialmente si estás haciendo MVVM, esta es una gran biblioteca. –

+0

¡Gracias, lo comprobaré! Por alguna razón, mi cerebro acaba de cambiar "ReactiveUI" por "extensiones reactivas". (No estaba al tanto de la biblioteca.) –

Cuestiones relacionadas