Il thread chiamante non può accedere a questo object perché lo possiede un thread diverso

Il mio codice è il seguente

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() != string.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); } } 

Il passaggio objUDMCountryStandards.Country = txtSearchCountry.Text.Trim() != string.Empty ? txtSearchCountry.Text : null; objUDMCountryStandards.Country = txtSearchCountry.Text.Trim() != string.Empty ? txtSearchCountry.Text : null; in ottenere i dati della griglia genera un’eccezione

Il thread chiamante non può accedere a questo object perché lo possiede un thread diverso.

Cosa c’è che non va qui?

Questo è un problema comune con le persone che iniziano. Ogni volta che aggiorni gli elementi dell’interfaccia utente da un thread diverso dal thread principale, devi utilizzare:

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

È inoltre ansible utilizzare control.Dispatcher.CheckAccess() per verificare se il thread corrente è proprietario del controllo. Se lo possiede, il tuo codice sembra normale. Altrimenti, usa il modello sopra.

Un altro buon utilizzo di Dispatcher.Invoke è l’aggiornamento immediato dell’interfaccia utente in una funzione che esegue altre attività:

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

Lo uso per aggiornare il testo del pulsante su ” Elaborazione in corso … ” e disabilitarlo mentre WebClient richieste WebClient .

Per aggiungere i miei 2 centesimi, l’eccezione può verificarsi anche se si chiama il codice tramite System.Windows.Threading.Dispatcher.CurrentDispatcher.Invoke() .
Il punto è che devi chiamare Invoke() del Dispatcher del controllo a cui stai tentando di accedere , che in alcuni casi potrebbe non essere lo stesso di System.Windows.Threading.Dispatcher.CurrentDispatcher . Quindi, invece, dovresti usare YourControl.Dispatcher.Invoke() per sicurezza. Ho sbattuto la testa per un paio d’ore prima di rendermene conto.

Se qualcuno tenta di lavorare con BitmapSource in WPF e thread e ha lo stesso messaggio: chiama il metodo Freeze() prima di passare a BitmapSource come parametro del thread.

questo è successo con me perché ho provato ad access UI al componente access UI in another thread insted of UI thread

come questo

 private void button_Click(object sender, RoutedEventArgs e) { new Thread(SyncProcces).Start(); } private void SyncProcces() { string 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); } 

per risolvere questo problema, avvolgi qualsiasi chiamata ui all’interno di ciò che Candide ha menzionato sopra nella sua risposta

 private void SyncProcces() { string 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 ); } 

È necessario aggiornare l’interfaccia utente, quindi utilizzare

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

Per qualche motivo la risposta di Candide non è stata costruita. È stato utile, tuttavia, poiché mi ha portato a trovarlo, il che ha funzionato perfettamente:

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

Il problema è che si chiama GetGridData da un thread in background. Questo metodo accede a diversi controlli WPF associati al thread principale. Qualsiasi tentativo di accedervi da un thread in background porterà a questo errore.

Per tornare alla discussione corretta devi usare SynchronizationContext.Current.Post . Tuttavia in questo caso particolare sembra che la maggior parte del lavoro che stai facendo sia basato sull’interfaccia utente. Quindi dovresti creare un thread in background solo per tornare immediatamente al thread dell’interfaccia utente e fare un po ‘di lavoro. È necessario riordinare il codice un po ‘in modo che possa eseguire il costoso lavoro sul thread in background e quindi postare i nuovi dati sul thread dell’interfaccia utente

Ho anche scoperto che System.Windows.Threading.Dispatcher.CurrentDispatcher.Invoke() non è sempre il dispatcher del controllo del target, proprio come dotNet ha scritto nella sua risposta. Non ho avuto accesso al dispatcher del controllo, quindi ho usato Application.Current.Dispatcher e ho risolto il problema.

Inoltre, un’altra soluzione garantisce che i controlli vengano creati nel thread dell’interfaccia utente, ad esempio, non da un thread di background worker.

Come accennato qui , Dispatcher.Invoke potrebbe bloccare l’interfaccia utente. Utilizzare invece Dispatcher.BeginInvoke .

Ecco una comoda class di estensione per semplificare il controllo e la chiamata al richiamo del dispatcher.

Esempio di utilizzo: (chiamata dalla finestra WPF)

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

Classe di estensione:

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

Questo funziona per me.

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

Ho continuato a ricevere l’errore quando ho aggiunto i combobox in cascata alla mia applicazione WPF e ho risolto l’errore utilizzando questa 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 ); } 

Per maggiori dettagli, consultare 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