2011-06-29 8 views
10

Jestem całkiem nowy dla MVVM, więc przepraszam, jeśli ten problem ma dobrze znane rozwiązanie.Nie blokujące właściwości opóźnione w modelu MVVM

Budujemy grupę klas modeli, które mają pewne podstawowe właściwości, które są ładowane z góry, a także niektóre dodatkowe właściwości, które mogą być leniwym ładowaniem na żądanie poprzez wywołanie interfejsu API sieci Web (aktualizacja: wyjaśnienie, byłoby to wywołanie web API dla każdej obciążonej leniwie nieruchomości).

Zamiast wielu modeli wydaje się rozsądne posiadanie jednego modelu z logiką ładowania. Wydaje się jednak, że właściwości Leni-Load nie powinny blokować podczas dostępu, tak że gdy widok wiąże się z ViewModel i wiąże się z Modelem, nie blokujemy wątku UI.

Jako takie, myślałem o wzór coś wzdłuż linii, gdy leniwy właściwość w modelu jest dostępny rozpoczyna się asynchroniczne pobieranie, a następnie natychmiast zwraca wartość domyślną (np. null). Po zakończeniu pobierania asynchronicznego zostanie wywołane zdarzenie PropertyChanged, aby narzędzie ViewModel/View mogło ponownie połączyć się z pobraną wartością.

Próbowałem to na zewnątrz i wydaje się działać całkiem dobrze, ale zastanawiałem się:

  1. Czy są jakieś pułapki do takiego podejścia, że ​​nie dowiedział się o jeszcze, ale będzie działać w jak aplikacja zwiększa złożoność?
  2. Czy istnieje istniejące rozwiązanie tego problemu albo wbudowane w środowisko, albo które jest powszechnie stosowane jako element zewnętrznego schematu?
+0

Możliwym problemem, jaki mogę wymyślić, jest konieczność wysłuchania zdarzenia PropertyChanged na wszystkich tych leniwych ładowarkach, co oznacza, że ​​jeśli masz właściwość lub funkcję, która opiera się na wielu z tych ładowarek, będzie musiała poczekaj, aż wszystkie ładowniki, na których się opiera, zakończą przed wykonaniem własnego kodu. Może to spowodować konieczność napisania dużej ilości logiki, która w przeciwnym razie mogłaby zostać napisana jako pojedyncza kombinacja wątków, łącząca pobieranie "leniwych ładowarek" synchronicznie w obrębie tego osobnego wątku. –

+0

@Tymothy - Dobry punkt. Już o tym myślałem i wydaje mi się, że ze względu na naturę leniwie ładowanych danych jest mało prawdopodobne, aby cokolwiek zależało od wielu fragmentów leniwych danych. Jest prawdopodobne, że wiele rzeczy będzie zależeć od jednego kawałka leniwych danych, ale nie sądzę, że stanowi problem. –

+0

Używam dokładnego podejścia opisanego powyżej i działa bardzo dobrze. – Jeff

Odpowiedz

6

Zrobiłem coś takiego w przeszłości i jedyną rzeczą, o której zapomniałem, jest to, że nie można nazwać swojej asynchronicznej własności za pomocą jakiegokolwiek kodu z tyłu i oczekiwać, że będzie miała jakąś wartość.

Więc jeśli mam leniwą listę Customer.Products, nie mogę odwołać się do Customer.Products.Count w kodzie z tyłu, ponieważ po raz pierwszy nazywa się to wartość NULL lub 0 (w zależności od tego, czy utworzyć pustą kolekcję, czy nie)

Poza tym zadziałało świetnie dla wiązań. Używałem biblioteki Async CTP do wykonywania asynchronicznych wywołań, które uważam za absolutnie cudowne z czegoś takiego.

public ObservableCollection<Products> Products 
{ 
    get 
    { 
     if (_products == null) 
      LoadProductsAsync(); 

     return _products; 
    } 
    set { ... } 
} 

private async void LoadProductsAsync() 
{ 
    Products = await DAL.LoadProducts(CustomerId); 
} 

Aktualizacja

Pamiętam inną rzeczą miałem problemów z danych, które było rzeczywiście była zerowa. Jeśli Customer.Products rzeczywiście zwróciło wartość NULL z serwera, musiałem wiedzieć, że metoda asynchroniczna działała poprawnie i że rzeczywista wartość była zerowa, więc nie powtórzyła metody asynchronicznej.

Nie chciałem również, aby metoda asynchroniczna była uruchamiana dwukrotnie, jeśli ktoś wywołał metodę Get 2 raz przed zakończeniem pierwszego połączenia asynchronicznego.

Rozwiązałem to w czasie, mając właściwość Is[AsyncPropertyName]Loading/ed dla każdej właściwości async i ustawiając ją na true podczas pierwszego asynchronicznego połączenia, ale nie byłem naprawdę zadowolony z konieczności utworzenia dodatkowej właściwości dla wszystkich właściwości asynchronicznych.

+0

* (Dodano podświetlanie składni) * –