2012-06-15 10 views
7

Sto cercando di implementare alcuni comportamenti di limitazione in uno dei miei viewmodels. È un'applicazione Silverlight, tuttavia non penso che sia particolarmente importante.Event throttling/accodamento - Estensioni reattive?

consideri una classe con tre proprietà:

  • Property1
  • Property2
  • Property3

Ogni volta che una di queste proprietà viene aggiornato, un aggiornamento è necessario.

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

I miei obiettivi sono i seguenti:

  • Se un aggiornamento è in corso, si dovrebbe idealmente annullare la chiamata al server, ed emettere una nuova richiesta
  • Se una proprietà viene modificata, dovremmo lasciare una piccola finestra temporale (forse 0,1 secondi) dove aspettiamo ulteriori cambiamenti. In questo modo, se vengono modificate più proprietà rapidamente (ad esempio, a livello di codice), non inviamo spam al server con richieste. Va bene che la finestra da 0,1 secondi si ripristini a ogni modifica, ma non è necessaria.

Se è importante, sto utilizzando un'implementazione ChannelFactory per la chiamata al server.

Che tipo di motivi posso utilizzare per realizzare questo? È qualcosa con cui le estensioni reattive possono aiutarmi?

Edit:

Marcatura risposta di Paolo come corrette. Mentre ReactiveUI non funziona attualmente contro silverlight5, delinea chiaramente le fasi di approccio/composizione per risolvere il problema usando Rx.

+1

Rx sostiene sicuramente questa, vedere http://rxwiki.wikidot.com/101samples#toc29 - circa annullarlo - dare un'occhiata a CancellationToken da Attività –

risposta

6

Ecco come si dovrebbe fare questo 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); 

Aggiornamento: Ecco come garantire che c'è solo uno in esecuzione alla volta, con l'avvertenza che si può ottenere out-of-order risultati.

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

Il comportamento descritto, sarebbe in realtà forse non auspicabile, dal momento che se le proprietà continuano a cambiare, ci si ritroverà con una coda di vecchie richieste per il rilascio - si potrebbe ottimizzare questo se hai fatto qualcosa di simile a un Operatore "BufferingSwitch()" che non ha restituito i suoi risultati fino a quando non era sicuro che non ci fossero cambiamenti - sarebbe stato bello scrivere.

Morale della favola, Async è complicata ™ :)

+0

Grazie, sembra quello di cui ho bisogno a prima vista. È valido per Silverlight? Non riesco a trovare il metodo di estensione WhenAny per fare un tentativo. –

+0

@ShaunRowan: tale estensione proviene da ReactiveUI (http://www.reactiveui.net). Le versioni precedenti (v2) supportano Silverlight. La versione corrente (v3) no. Soprattutto se stai facendo MVVM, questa è davvero una grande biblioteca. –

+0

Grazie, controllerò! Per qualche ragione il mio cervello si è appena scambiato "ReactiveUI" con "estensioni reattive". (Non ero a conoscenza della biblioteca.) –

Problemi correlati