2010-03-17 14 views
5

Mam (niezwirtualizowanych) ItemsControl, który wiąże swój ItemsSource z ObeservableCollection instancji ViewModel. Teraz po załadowaniu dużej ilości instancji modeli wszystkie kompilacje ViewModel muszą zostać dodane do tej ObservableCollection. Jak mogę dodać dużą liczbę ViewModels bez konieczności zawieszenia wątku interfejsu użytkownika?ItemsControl.ItemsSource MVVM performance

Przypuszczam, że wątek interfejsu użytkownika zawiesza się, ponieważ za każdym razem, gdy dodawana jest nowa pozycja, ItemsControl musi się aktualizować i układ itd. W kółko.

  • powinienem zawiesić wiązanie dodać wszystkie elementy, a następnie wznowić? Jeśli tak to jak?
  • powinienem zastąpić ObservableCollection na wdrożenie AddRange więc tylko 1 CollectionChanged zdarzenie jest zwolniony za dodanie wielu elementy? Lub alternatywnie po prostu wymienić całej kolekcji?
  • Czy lepiej jest dodać osobno każdą pozycję i zadzwonić pod numer Dispatcher.Invoke dla każdej pozycji osobno? Tak więc często odblokowuję .

Jak radzisz sobie z dużymi listami dynamicznymi, których nie można zwirtualizować?

+0

Czego używasz? WPF/Silverlight? WinForms? Coś innego? – slugster

+0

Powinno być oczywiste, że nie są to formularze systemu Windows, ponieważ żadna z wymienionych klas nie istnieje w formularzach okien. – bitbonk

+0

Czy istnieje jakiś szczególny powód, dla którego twoja kontrola przedmiotów nie może korzystać z wirtualizacji interfejsu użytkownika? –

Odpowiedz

10

Można utworzyć klasę pochodzącą z ObservableCollection który pozwala tymczasowo zawiesić CollectionChanged wydarzenia tak:

public class SuspendableObservableCollection : ObservableCollection 
{ 
    private bool suspended; 

    public bool Suspended 
    { 
     get 
     { 
      return this.suspended; 
     } 
     set 
     { 
      this.suspended = value; 
      OnCollectionChanged(new NotifyCollectionChangedEventArgs(
       NotifyCollectionChangedAction.Reset)); 
     } 
    } 

    protected override void OnCollectionChanged(
     NotifyCollectionChangedEventArgs args) 
    { 
     if (!Suspended) 
     { 
      base.OnCollectionChanged(args); 
     } 
    } 
} 
+0

Moje pytanie dotyczy raczej tego, w jaki sposób mogę poprawić wydajność, a nie jak wdrożyć taką kolekcję. Również, jeśli tymczasowo zawiesię takie wydarzenia jak Ty, ItemsControl wyświetli zły stan po wznowieniu zawieszenia. Jeśli podniesione zostanie nowe zdarzenie CollectionChanged, nadal będzie wyświetlany niepoprawny stan, ponieważ nie dostał wszystkich modyfikacji, które zostały wprowadzone do kolekcji podczas jej zawieszenia. – bitbonk

+0

1) Czy wdrożenie takiej kolekcji nie poprawi wydajności? 2) Dodałem zdarzenie resetowania w celu rozwiązania problemu, który opisałeś. –

+0

Wygląda na to, że nie poprawia to wydajności. Prawdopodobnie dlatego, że tze ItemsControl musi generować wiele kontroli pozycji jednocześnie. Sądzę więc, że lepszym rozwiązaniem byłoby dodanie niektórych elementów osobno za pomocą (Rozpocznij) Wywoływanie wiele razy. – bitbonk

0
<ItemsControl IsAsync="True" ... /> 
+0

Prawdopodobnie miałeś na myśli ''. Sam 'ItemsControl' nie ma tej właściwości. Ta właściwość powinna być używana zamiennie: "nie powinno być zbyt wielu scenariuszy, w których musisz używać właściwości IsAsync." Zalecenia .NET zalecają, aby definiować właściwości wolniejsze o kilka rzędów niż zestaw pól. " – bitbonk

+0

ah Myślałem, że każdy Selektor ma własność IsAsync. Kiedy ładujesz okno, które ładuje dużo danych w sposób nie asynchroniczny, dostajesz czarne okno lub zawiesza się (tak stało się w moim przypadku używając IsAsync = True teraz). Dlatego zaleca się używanie IsAsync! – Elisabeth

+0

Jeśli sugerujesz zrobić " "to nie działa." IsAsnyc' działa tylko wtedy, gdy sam DataSource nie jest dostępny od razu lub nie W moim przypadku DataSource jest dostępny od razu, ale zawiera wiele pozycji. Przeczytaj tutaj, aby uzyskać więcej szczegółowych informacji na temat problemu: http://goo.gl/BwA1 – bitbonk