Die Aufgabenstellung beschreibt, das innerhalb eine ViewModels Daten aus einer Datenbank ausgelesen und über der Netzwerkverbindung noch weiter verarbeitet werden müssen. Hier liegt es auf der Hand, dass eine asynchrone Lösung her muss, sprich es muss unter allen Umständen verhindert werden, dass die UI blockiert.

Wie man das machen kann, zeige ich wie folgt:

Ich erstelle mir vorerst einen einfachen Delegate.

1 private delegate void AsyncAwsDelegate();

Im Konstruktor der ViewModels, bzw in einem Command wird dann an diesem Delegate ein BeginInvoke aufgerufen, der die Methode zur asynchronen Verarbeitung zugewiesen bekommt.

1 public MainViewModel() 2 { 3 AsyncAwsDelegate del = (FetchItemsAsync); 4 del.BeginInvoke(null, null); 5 }

In dieser Methode findet dann der Prozess statt, wo die Items verarbeitet und einer ObservableCollection<T> hinzugefügt werden.

1 private void FetchItemsAsync() 2 { 3 var items = _dataLayer.Items.ToList(); 4 items.ForEach(i => Items.Add(_aws.ItemLookup(i.ItemId))); 5 }

Das geht leider nicht ohne Dispatcher, sprich wenn ich die “normale” ObservableCollection verwenden würde, müsste ich zuerst in den UI Thread gelangen, ansonsten knallt es.

Dazu konnte ich eine nette spezialisierte Klasse finden, die mir diese Arbeit abnimmt.

1 public class DispatchingObservableCollection<T> : ObservableCollection<T> 2 { 3 private readonly Dispatcher _currentDispatcher; 4 5 /// <summary> 6 /// The default constructor of the ObservableCollection 7 /// </summary> 8 public DispatchingObservableCollection() 9 { 10 //Assign the current Dispatcher (owner of the collection) 11 _currentDispatcher = Dispatcher.CurrentDispatcher; 12 } 13 14 /// <summary> 15 /// Executes this action in the right thread 16 /// </summary> 17 ///<param name="action">The action which should be executed</param> 18 private void DoDispatchedAction(Action action) 19 { 20 if (_currentDispatcher.CheckAccess()) 21 action(); 22 else 23 _currentDispatcher.Invoke(DispatcherPriority.DataBind, action); 24 } 25 26 /// <summary> 27 /// Clears all items 28 /// </summary> 29 protected override void ClearItems() 30 { 31 DoDispatchedAction(() => base.ClearItems()); 32 } 33 34 /// <summary> 35 /// Inserts a item at the specified index 36 /// </summary> 37 ///<param name="index">The index where the item should be inserted</param> 38 ///<param name="item">The item which should be inserted</param> 39 protected override void InsertItem(int index, T item) 40 { 41 DoDispatchedAction(() => base.InsertItem(index, item)); 42 } 43 }

Da die ObservableCollection das INotifyPropertyChanged Interface implementiert, brauch ich auch nicht mehr dafür Sorge tragen, dass sich bei jedem Zufügen eines Items die UI aktualisieren muss.

Viel Spaß beim entwickeln : )

Asynchrones Befüllen einer ObservableCollection<T> in einem ViewModel
Markiert in:    

2 thoughts on “Asynchrones Befüllen einer ObservableCollection<T> in einem ViewModel

Kommentare sind deaktiviert.