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