Вызывающий stream не может получить доступ к этому объекту, потому что ему принадлежит другой stream

Мой код выглядит следующим образом:

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

Шаг objUDMCountryStandards.Country = txtSearchCountry.Text.Trim() != string.Empty ? txtSearchCountry.Text : null; objUDMCountryStandards.Country = txtSearchCountry.Text.Trim() != string.Empty ? txtSearchCountry.Text : null; в результате получения данных сетки

Вызывающий stream не может получить доступ к этому объекту, потому что ему принадлежит другой stream.

Что здесь не так?

Это обычная проблема с началом работы с людьми. Всякий раз, когда вы обновляете элементы пользовательского интерфейса из streamа, отличного от основного streamа, вам необходимо использовать:

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

Вы также можете использовать control.Dispatcher.CheckAccess() чтобы проверить, принадлежит ли текущий stream элементу управления. Если он действительно владеет, ваш код выглядит нормально. В противном случае используйте шаблон выше.

Еще одно хорошее применение для Dispatcher.Invoke – это немедленное обновление пользовательского интерфейса в функции, которая выполняет другие задачи:

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

Я использую это, чтобы обновить текст кнопки до « Обработка … » и отключить ее при выполнении запросов WebClient .

Чтобы добавить мои 2 цента, исключение может возникнуть, даже если вы вызываете свой код через System.Windows.Threading.Dispatcher.CurrentDispatcher.Invoke() .
Дело в том, что вам нужно вызвать Invoke() Dispatcher элемента управления, к которому вы пытаетесь получить доступ , что в некоторых случаях может не совпадать с System.Windows.Threading.Dispatcher.CurrentDispatcher . Поэтому вместо этого вы должны использовать YourControl.Dispatcher.Invoke() чтобы быть в безопасности. Я уже несколько часов стучал головой, прежде чем понял это.

Если кто-то пытается работать с BitmapSource в WPF и streamах и имеет это же сообщение: сначала вызовите метод Freeze() прежде чем передать BitmapSource в качестве параметра streamа.

это произошло со мной, потому что я попытался получить access UI компоненту access UI в another thread insted of UI thread

как это

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

для решения этой проблемы, оберните любой вызов ui внутри того, что упоминал выше Кандид в своем ответе

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

Вам необходимо обновить пользовательский интерфейс, поэтому используйте

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

По какой-то причине ответ Кандиде не строился. Это было полезно, однако, поскольку это заставило меня найти это, которое отлично работало:

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

Проблема в том, что вы вызываете GetGridData из фонового streamа. Этот метод обращается к нескольким элементам управления WPF, которые привязаны к основному streamу. Любая попытка доступа к ним из фонового streamа приведет к этой ошибке.

Чтобы вернуться к правильному streamу, вы должны использовать SynchronizationContext.Current.Post . Однако в этом конкретном случае, похоже, большая часть работы, которую вы выполняете, основана на пользовательском интерфейсе. Следовательно, вы создадите фоновый stream, чтобы сразу вернуться к streamу пользовательского интерфейса и выполнить некоторую работу. Вам нужно немного реорганизовать свой код, чтобы он мог выполнять дорогостоящую работу в фоновом streamе, а затем публиковать новые данные в streamе пользовательского интерфейса

Я также обнаружил, что System.Windows.Threading.Dispatcher.CurrentDispatcher.Invoke() не всегда является диспетчером целевого управления, точно так же, как dotNet пишет в своем ответе. У меня не было доступа к диспетчеру управления, поэтому я использовал Application.Current.Dispatcher и он решил проблему.

Кроме того, другое решение гарантирует, что ваши элементы управления создаются в streamе пользовательского интерфейса, а не, например, streamом рабочего фона.

Как уже упоминалось, Dispatcher.Invoke может заморозить пользовательский интерфейс. Вместо этого следует использовать Dispatcher.BeginInvoke .

Вот удобный class расширений, который упрощает проверку и вызов диспетчера вызовов.

Пример использования: (вызов из windows WPF)

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

Класс расширения:

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

Это работает для меня.

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

Я продолжал получать ошибку, когда добавлял каскадные comboboxes в мое приложение WPF и разрешал ошибку с помощью этого 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 ); } 

Для получения дополнительной информации см. 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); к (DevLang-CSharp) & й = истина

Давайте будем гением компьютера.