Le thread appelant ne peut pas accéder à cet object car un thread différent le possède

Mon code est comme ci-dessous

public CountryStandards() { InitializeComponent(); try { FillPageControls(); } catch (Exception ex) { MessageBox.Show(ex.Message, "Country Standards", MessageBoxButton.OK, MessageBoxImage.Error); } } ///  /// Fills the page controls. ///  private void FillPageControls() { popUpProgressBar.IsOpen = true; lblProgress.Content = "Loading. Please wait..."; progress.IsIndeterminate = true; worker = new BackgroundWorker(); worker.DoWork += new System.ComponentModel.DoWorkEventHandler(worker_DoWork); worker.ProgressChanged += new System.ComponentModel.ProgressChangedEventHandler(worker_ProgressChanged); worker.WorkerReportsProgress = true; worker.WorkerSupportsCancellation = true; worker.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(worker_RunWorkerCompleted); worker.RunWorkerAsync(); } private void worker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e) { GetGridData(null, 0); // filling grid } private void worker_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e) { progress.Value = e.ProgressPercentage; } private void worker_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e) { worker = null; popUpProgressBar.IsOpen = false; //filling Region dropdown Standards.UDMCountryStandards objUDMCountryStandards = new Standards.UDMCountryStandards(); objUDMCountryStandards.Operation = "SELECT_REGION"; DataSet dsRegionStandards = objStandardsBusinessLayer.GetCountryStandards(objUDMCountryStandards); if (!StandardsDefault.IsNullOrEmptyDataTable(dsRegionStandards, 0)) StandardsDefault.FillComboBox(cmbRegion, dsRegionStandards.Tables[0], "Region", "RegionId"); //filling Currency dropdown objUDMCountryStandards = new Standards.UDMCountryStandards(); objUDMCountryStandards.Operation = "SELECT_CURRENCY"; DataSet dsCurrencyStandards = objStandardsBusinessLayer.GetCountryStandards(objUDMCountryStandards); if (!StandardsDefault.IsNullOrEmptyDataTable(dsCurrencyStandards, 0)) StandardsDefault.FillComboBox(cmbCurrency, dsCurrencyStandards.Tables[0], "CurrencyName", "CurrencyId"); if (Users.UserRole != "Admin") btnSave.IsEnabled = false; } ///  /// Gets the grid data. ///  /// The sender. /// Index of the page.( used in case of paging)  private void GetGridData(object sender, int pageIndex) { Standards.UDMCountryStandards objUDMCountryStandards = new Standards.UDMCountryStandards(); objUDMCountryStandards.Operation = "SELECT"; objUDMCountryStandards.Country = txtSearchCountry.Text.Trim() != ssortingng.Empty ? txtSearchCountry.Text : null; DataSet dsCountryStandards = objStandardsBusinessLayer.GetCountryStandards(objUDMCountryStandards); if (!StandardsDefault.IsNullOrEmptyDataTable(dsCountryStandards, 0) && (chkbxMarketsSearch.IsChecked == true || chkbxBudgetsSearch.IsChecked == true || chkbxProgramsSearch.IsChecked == true)) { DataTable objDataTable = StandardsDefault.FilterDatatableForModules(dsCountryStandards.Tables[0], "Country", chkbxMarketsSearch, chkbxBudgetsSearch, chkbxProgramsSearch); dgCountryList.ItemsSource = objDataTable.DefaultView; } else { MessageBox.Show("No Records Found", "Country Standards", MessageBoxButton.OK, MessageBoxImage.Information); btnClear_Click(null, null); } } 

L’étape objUDMCountryStandards.Country = txtSearchCountry.Text.Trim() != ssortingng.Empty ? txtSearchCountry.Text : null; objUDMCountryStandards.Country = txtSearchCountry.Text.Trim() != ssortingng.Empty ? txtSearchCountry.Text : null; dans obtenir des données de grid jette une exception

Le thread appelant ne peut pas accéder à cet object car un thread différent le possède.

Qu’est-ce qui ne va pas ici?

C’est un problème courant avec les gens qui commencent. Chaque fois que vous mettez à jour vos éléments d’interface utilisateur à partir d’un thread autre que le thread principal, vous devez utiliser:

 this.Dispatcher.Invoke(() => { ...// your code here. }); 

Vous pouvez également utiliser control.Dispatcher.CheckAccess() pour vérifier si le thread actuel possède le contrôle. Si cela lui appartient, votre code semble normal. Sinon, utilisez le modèle ci-dessus.

Un autre bon usage de Dispatcher.Invoke est la mise à jour immédiate de l’interface utilisateur dans une fonction qui effectue d’autres tâches:

 // Force WPF to render UI changes immediately with this magic line of code... Dispatcher.Invoke(new Action(() => { }), DispatcherPriority.ContextIdle); 

Je l’utilise pour mettre à jour le texte du bouton en ” Traitement … ” et le désactiver en faisant des requêtes WebClient .

Pour append mes 2 cents, l’exception peut se produire même si vous appelez votre code via System.Windows.Threading.Dispatcher.CurrentDispatcher.Invoke() .
Le fait est que vous devez appeler Invoke() du Dispatcher du contrôle auquel vous tentez d’accéder , ce qui dans certains cas peut ne pas être identique à System.Windows.Threading.Dispatcher.CurrentDispatcher . Donc, vous devriez plutôt utiliser YourControl.Dispatcher.Invoke() pour être sûr. Je me suis cogné la tête pendant quelques heures avant de m’en rendre compte.

Si quelqu’un essaie de travailler avec BitmapSource dans WPF et les threads et qu’il a le même message: appelez d’abord la méthode Freeze() avant de transmettre un BitmapSource tant que paramètre de thread.

cela s’est passé avec moi parce que j’ai essayé d’ access UI composant d’ access UI dans another thread insted of UI thread

comme ça

 private void button_Click(object sender, RoutedEventArgs e) { new Thread(SyncProcces).Start(); } private void SyncProcces() { ssortingng val1 = null, val2 = null; //here is the problem val1 = textBox1.Text;//access UI in another thread val2 = textBox2.Text;//access UI in another thread localStore = new LocalStore(val1); remoteStore = new RemoteStore(val2); } 

pour résoudre ce problème, encapsulez tout appel d’interface utilisateur à l’intérieur de ce que Candide a mentionné ci-dessus dans sa réponse.

 private void SyncProcces() { ssortingng val1 = null, val2 = null; this.Dispatcher.Invoke((Action)(() => {//this refer to form in WPF application val1 = textBox.Text; val2 = textBox_Copy.Text; })); localStore = new LocalStore(val1); remoteStore = new RemoteStore(val2 ); } 

Vous devez mettre à jour l’interface utilisateur, utilisez donc

 Dispatcher.BeginInvoke(new Action(() => {GetGridData(null, 0)})); 

Pour une raison quelconque, la réponse de Candide ne s’est pas construite. C’était utile, cependant, car cela m’a amené à trouver ceci, qui a parfaitement fonctionné:

 System.Windows.Threading.Dispatcher.CurrentDispatcher.Invoke((Action)(() => { //your code here... })); 

Le problème est que vous appelez GetGridData partir d’un thread d’arrière-plan. Cette méthode accède à plusieurs contrôles WPF liés au thread principal. Toute tentative d’y accéder depuis un thread d’arrière-plan entraînera cette erreur.

Pour revenir au bon thread, vous devez utiliser SynchronizationContext.Current.Post . Cependant, dans ce cas particulier, il semble que la majorité du travail que vous effectuez soit basée sur l’interface utilisateur. Par conséquent, vous créez un thread d’arrière-plan juste pour retourner immédiatement au thread d’interface utilisateur et faire un peu de travail. Vous devez légèrement modifier votre code pour qu’il puisse effectuer le travail coûteux sur le thread d’arrière-plan, puis publier les nouvelles données sur le thread d’interface utilisateur par la suite.

J’ai également constaté que System.Windows.Threading.Dispatcher.CurrentDispatcher.Invoke() n’est pas toujours un répartiteur du contrôle de la cible, comme l’a écrit dotNet dans sa réponse. Je n’ai pas eu access au propre répartiteur du contrôle, j’ai donc utilisé Application.Current.Dispatcher et cela a résolu le problème.

En outre, une autre solution consiste à vous assurer que vos contrôles sont créés dans un thread d’interface utilisateur, et non par un thread de travail en arrière-plan, par exemple.

Comme mentionné ici , Dispatcher.Invoke pourrait geler l’interface utilisateur. Devrait utiliser Dispatcher.BeginInvoke place.

Voici une classe d’extension pratique pour simplifier la vérification et l’appel de l’appel du répartiteur.

Exemple d’utilisation: (appel depuis la fenêtre WPF)

 this Dispatcher.InvokeIfRequired(new Action(() => { logTextbox.AppendText(message); logTextbox.ScrollToEnd(); })); 

Classe d’extension:

 using System; using System.Windows.Threading; namespace WpfUtility { public static class DispatcherExtension { public static void InvokeIfRequired(this Dispatcher dispatcher, Action action) { if (dispatcher == null) { return; } if (!dispatcher.CheckAccess()) { dispatcher.BeginInvoke(action, DispatcherPriority.ContextIdle); return; } action(); } } } 

Cela fonctionne pour moi.

  new Thread(() => { Thread.CurrentThread.IsBackground = false; Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, (SendOrPostCallback)delegate { //Your Code here. }, null); }).Start(); 

J’ai continué à recevoir l’erreur lorsque j’ai ajouté des boîtes à options en cascade à mon application WPF et j’ai résolu l’erreur en utilisant cette API:

  using System.Windows.Data; private readonly object _lock = new object(); private CustomObservableCollection _myUiBoundProperty; public CustomObservableCollection MyUiBoundProperty { get { return _myUiBoundProperty; } set { if (value == _myUiBoundProperty) return; _myUiBoundProperty = value; NotifyPropertyChanged(nameof(MyUiBoundProperty)); } } public MyViewModelCtor(INavigationService navigationService) { // Other code... BindingOperations.EnableCollectionSynchronization(AvailableDefectSubCategories, _lock ); } 

Pour plus d’informations, consultez la page https://msdn.microsoft.com/query/dev14.query?appId=Dev14IDEF1&l=EN-US&k=k(System.Windows.Data.BindingOperations.EnableCollectionSynchronization);k(TargetFrameworkMoniker-.NETFramework,Version % 3Dv4.7); k (DevLang-csharp) & rd = true