Problème de thread «Le thread appelant ne peut pas accéder à cet object car un thread différent le possède». Des solutions?

J’ai une liste qui contient les noms de fichiers. J’ai une autre liste qui contient les actions possibles pour renommer ces fichiers. Enfin, j’ai une étiquette qui affiche un aperçu du résultat. Lorsqu’un object est sélectionné dans chacune des listes, je souhaite afficher l’aperçu. Vous ne pouvez sélectionner qu’un fichier mais une ou plusieurs actions. J’utilise WPF / Xaml pour mon interface utilisateur. J’ai choisi d’effectuer mon aperçu avec un fil.

Voici une partie de mon code:

private Thread _thread; public MainWindow() { InitializeComponent(); _thread = new Thread(DoWork); } public void DoWork() { while (true) { FileData fileData = listViewFiles.SelectedItem as FileData; // ERROR HERE if (fileData != null) { ssortingng name = fileData.FileName; foreach (var action in _actionCollection) { name = action.Rename(name); } previewLabel.Content = name; } Thread.Sleep(1000); } } private void listViewFiles_SelectionChanged(object sender, SelectionChangedEventArgs e) { _thread.Start(); } 

Au moment de l’exécution, j’obtiens l’erreur “Le thread appelant ne peut pas accéder à cet object car un autre thread le possède.” sur le FileData fileData = listViewFiles.SelectedItem as FileData; ligne. Savez-vous que dois-je faire?

Vous ne pouvez pas modifier ou accéder à l’interface utilisateur à partir d’un thread non-UI. Donc, si vous voulez toujours utiliser un autre thread, vous devez d’abord append un type de modèle (pour plus d’informations sur la liaison et le modèle, recherchez “wpf mvvm”), puis liez-vous listViewFiles.SelectedItem à une propriété de celle-ci. model cela vous permettra d’accéder à SelectedValue à travers les threads. Deuxièmement, vous devez séparer toute la logique qui modifie l’UI en méthode ou utilise lambda pour qu’elle ressemble à ceci:

 public void DoWork() { while (true) { FileData fileData = Model.SelectedValue; if (fileData != null) { ssortingng name = fileData.FileName; foreach (var action in _actionCollection) { name = action.Rename(name); } this.Dispatcher.Invoke((Action)()=> //use Window.Dispatcher { label3.Content = fileData.FileName; label4.Content = name; }); } Thread.Sleep(1000); } } 

UPD. Quelques mots supplémentaires sur la synchronisation avec l’interface utilisateur: dans WPF, chaque object d’interface utilisateur hérite de la classe DispatcherObject . Ainsi, tous les access à des objects de ce type ne peuvent être créés qu’à partir du thread dans lequel cet object a été créé. Si vous souhaitez accéder à DispatcherObject (DO) à partir d’un autre thread, vous devez utiliser la DO.Dispatcher.Invoke(Delegate) . votre code pour faire du thread. Donc, en conclusion, pour exécuter du code dans le thread d’interface utilisateur, vous devez utiliser Dipatcher de n’importe quel élément d’interface utilisateur. Dans ce cas, nous utilisons Dispatcher of Window (supposons que ce code soit dans le code de fenêtre derrière).

La réponse simple est que vous ne pouvez pas faire cela: le thread A ne peut pas accéder directement aux objects winforms (contrôles) que le thread B a créés.

En pratique, vous pouvez utiliser un délégué pour exécuter cela en toute sécurité sur l’autre thread ala:

 form.Invoke(new MethodInvoker(() => { FileData fileData = listViewFiles.SelectedItem as FileData; // ERROR HERE if (fileData != null) { ssortingng name = fileData.FileName; foreach (var action in _actionCollection) { name = action.Rename(name); } previewLabel.Content = name; } })); 

Toutefois, vous souhaiterez peut-être simplement utiliser un travailleur en arrière-plan: http://msdn.microsoft.com/en-us/library/8xs8549b.aspx

Plus en détail sur: http://weblogs.asp.net/justin_rogers/pages/126345.aspx