2012-06-15 21 views
7

Chciałbym wprowadzić pewne ograniczające działanie do jednej z moich modeli widoku. Jest to aplikacja silverlight, ale nie sądzę, że jest to szczególnie ważne.Ograniczanie/ustawianie zdarzeń - Rozszerzenia reaktywne?

Rozważmy klasę z trzech właściwości:

  • Property1
  • Property2
  • Property3

Gdy jeden z tych właściwości jest aktualizowana, odświeżenie jest konieczne.

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

Moje cele są następujące:

  • Jeśli Refresh jest w toku, powinniśmy idealnie zakończyć połączenie z serwerem i wydawać nowe żądanie
  • Jeśli właściwość zostanie zmieniona, powinniśmy zostawić trochę czasu (być może 0,1 sekundy), w którym czekamy na dodatkowe zmiany. W ten sposób, jeśli wiele właściwości zostanie szybko zmienionych (na przykład programowo), nie spamujemy serwera za pomocą żądań. Jest OK, aby to 0,1-sekundowe okno było resetowane przy każdej zmianie, ale nie było wymagane.

Jeśli to ma znaczenie, używam implementacji ChannelFactory dla wywołania serwera.

Jakiego rodzaju wzorców można użyć, aby to osiągnąć? Czy jest to coś, co może mi pomóc reaktywne rozszerzenie?

Edit:

Znakowanie odpowiedź Pawła prawidłowe. Podczas, gdy ReactiveUI nie działa obecnie przeciwko silverlight5, wyraźnie określa kroki podejścia/składu do rozwiązania problemu za pomocą Rx.

+1

Rx zdecydowanie popiera to zobaczyć http://rxwiki.wikidot.com/101samples#toc29 - o anulowaniu to - spójrz na CancellationToken z Zadania –

Odpowiedz

6

Oto jak można to zrobić z 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); 

Aktualizacja: Oto sposób, aby zagwarantować, że istnieje tylko jeden działa w czasie, z zastrzeżeniem, że można uzyskać out-of-order wyniki.

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

opisać zachowanie, to rzeczywiście może nie być pożądane, ponieważ jeśli właściwości ciągle się zmienia, będziesz skończyć z kolejki starych wniosków o wydanie - można zoptymalizować to jeśli się coś jak "BufferingSwitch()" operator, który nie zwrócił wyników, dopóki nie było pewności, że nie ma żadnych zmian - to byłoby naprawdę fajnie pisać.

Morał z tej historii, asynchroniczny jest skomplikowany ™ :)

+0

Dzięki, wygląda na to, czego potrzebuję na pierwszy rzut oka. Czy to dotyczy silverlight? Nie mogę znaleźć metody rozszerzenia WhenAny, aby spróbować. –

+0

@ShaunRowan: To rozszerzenie pochodzi z ReactiveUI (http://www.reactiveui.net). Poprzednie wersje (v2) obsługują Silverlight. Obecna wersja (v3) nie. Zwłaszcza jeśli robisz MVVM, jest to naprawdę świetna biblioteka. –

+0

Dzięki, sprawdzę to! Z jakiegoś powodu mój mózg po prostu zamienił "ReactiveUI" na "reaktywne rozszerzenia". (Nie wiedziałem o bibliotece.) –

Powiązane problemy