El hilo de llamada no puede acceder a este objeto porque lo posee un hilo diferente

Mi código es el siguiente

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

El paso objUDMCountryStandards.Country = txtSearchCountry.Text.Trim() != string.Empty ? txtSearchCountry.Text : null; objUDMCountryStandards.Country = txtSearchCountry.Text.Trim() != string.Empty ? txtSearchCountry.Text : null; en obtener datos de red arroja excepción

El hilo de llamada no puede acceder a este objeto porque lo posee un hilo diferente.

¿Qué pasa aquí?

Este es un problema común entre las personas que comienzan. Cada vez que actualice sus elementos de la interfaz de usuario de un hilo que no sea el hilo principal, debe usar:

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

También puede usar control.Dispatcher.CheckAccess() para comprobar si el hilo actual posee el control. Si es el propietario, tu código se ve como normal. De lo contrario, use el patrón de arriba.

Otro buen uso de Dispatcher.Invoke es la actualización inmediata de la IU en una función que realiza otras tareas:

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

Lo utilizo para actualizar el texto del botón a ” Procesando … ” y lo deshabilito al hacer solicitudes de WebClient .

Para agregar mis 2 centavos, la excepción puede ocurrir incluso si llama a su código a través de System.Windows.Threading.Dispatcher.CurrentDispatcher.Invoke() .
El punto es que debe llamar a Invoke() del Dispatcher del control al que está intentando acceder , que en algunos casos puede no ser el mismo que System.Windows.Threading.Dispatcher.CurrentDispatcher . Por lo tanto, en su lugar, debe usar YourControl.Dispatcher.Invoke() para estar seguro. Me estaba golpeando la cabeza por un par de horas antes de darme cuenta de esto.

Si alguien intenta trabajar con BitmapSource en WPF y subprocesos y tiene el mismo mensaje: simplemente llame primero al método Freeze() antes de pasar un BitmapSource como un parámetro de subproceso.

esto sucedió conmigo porque traté de access UI componente access UI en another thread insted of UI thread

Me gusta esto

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

para resolver este problema, envuelva cualquier llamada ui dentro de lo que Candide mencionó anteriormente en su respuesta

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

Necesita actualizar a la interfaz de usuario, así que use

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

Por alguna razón, la respuesta de Candide no se construyó. Fue útil, sin embargo, ya que me llevó a encontrar esto, que funcionó perfectamente:

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

El problema es que está llamando a GetGridData desde un hilo de fondo. Este método tiene acceso a varios controles WPF que están vinculados al hilo principal. Cualquier bash de acceder a ellos desde un hilo de fondo dará lugar a este error.

Para volver al hilo correcto, debe usar SynchronizationContext.Current.Post . Sin embargo, en este caso particular, parece que la mayoría del trabajo que está haciendo se basa en la interfaz de usuario. Por lo tanto, estaría creando un hilo de fondo solo para regresar inmediatamente al hilo de la interfaz de usuario y hacer algún trabajo. Necesita refactorizar su código un poco para que pueda hacer el trabajo costoso en el hilo de fondo y luego publicar los datos nuevos en el hilo de la interfaz de usuario luego

También encontré que System.Windows.Threading.Dispatcher.CurrentDispatcher.Invoke() no siempre es el despachador del control de destino, tal como dotNet escribió en su respuesta. No tuve acceso al despachador del control, así que utilicé Application.Current.Dispatcher y resolvió el problema.

Además, otra solución es garantizar que sus controles se creen en el hilo de la interfaz de usuario, no por un hilo de trabajo en segundo plano, por ejemplo.

Como se mencionó aquí , Dispatcher.Invoke podría congelar la IU. Debería usar Dispatcher.BeginInvoke lugar.

Aquí hay una práctica clase de extensión para simplificar la invocación del comprobador y del llamador llamante.

Uso de la muestra: (llamada desde la ventana de WPF)

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

Clase de extensión:

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

Esto funciona para mí

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

Seguí recibiendo el error cuando agregué cuadros combinados en cascada a mi aplicación WPF y resolví el error al usar esta 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 ); } 

Para obtener detalles, consulte 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