ObservableCollection et threading

J'ai un ObservableCollection dans ma classe. Et plus loin dans ma classe, j'ai un fil. De ce fil, je voudrais ajouter à mon ObservableCollection. Mais je ne peux pas faire ceci:

ce type de CollectionView ne prend pas en charge les modifications apportées à son SourceCollection à partir d'un thread différent du thread du répartiteur.

Notez que cela ne se produit pas à partir du thread de L'interface utilisateur, donc je n'ai pas accès au répartiteur.

26
demandé sur Dave Clemmer 2010-02-19 03:17:28

3 réponses

L'approche de JaredPar est valide. Une autre approche à considérer est l'utilisation d'un thread safe ObservableCollection au lieu du ObservableCollection intégré. Il y a quelques implémentations là-bas, mais l'implémentation de Sasha Barber et la classe CLinq collection continue sont quelques-unes des meilleures à mon avis. En interne, ces classes utilisent essentiellement l'approche décrite par JaredPar, mais l'encapsulent dans la classe collection.

16
répondu Szymon Rozga 2012-09-18 17:36:23

La meilleure façon de résoudre ce problème est de passer l'objet Dispatcher à la méthode start du thread d'arrière-plan.

void DoBackgroundOperation(ObservableCollection<SomeType> col) {
  var dispatcher = Dispatcher.CurrentDispatcher;
  ThreadStart start = () => BackgroundStart(dispatcher, col);
  var t = new Thread(start);
  t.Start();
}

private static void BackgroundStart(
    Dispatcher dispatcher, 
    ObservableCollection<SomeType> col) {
  ...
  SomeType t = GetSomeTypeObject();
  Action del = () => col.Add(t);
  dispatcher.Invoke(del);
}

Maintenant, plus tard, lorsque vous devez ajouter à la collection, vous pouvez utiliser l'INTERFACE utilisateur Dispatcher objet.

Comme l'a souligné @Reed, une solution plus générale est obtenue en utilisant SynchronizationContext. Voici un exemple de style fonctionnel utilisant SynchronizationContext pour créer un délégué responsable de l'ajout de nouvelles valeurs. Cela a l'avantage de cacher à la fois la collection et le modèle de threading du code la création de l'objet.

void DoBackgroundOperation(ObservableCollection<SomeType> col) {
  var context = SynchronizationContext.Current;
  Action<SomeType> addFunc = (SomeType st) => context.Send(() => col.Add(st), null);
  ThreadStart start = () => BackgroundStart(addFunc);
  var t = new Thread(start);
  t.Start();
}

private static void BackgroundStart(Action<SomeType> addFunc) {
  ...
  SomeType t = GetSomeTypeObject();
  addFunc(t);
}
13
répondu JaredPar 2010-02-19 00:28:26

In.Net 4.5, vous pouvez utiliser les collections Thread-safe, ConcurrentDictionary, ConcurrentBag etc., selon vos besoins: http://msdn.microsoft.com/en-us/library/dd997305.aspx

Veuillez lire aussi: http://www.codeproject.com/Articles/208361/Concurrent-Observable-Collection-Dictionary-and-So

5
répondu Cornel Marian 2013-10-19 20:52:04