調用線程無法訪問該對象,因爲其他線程擁有它

本文翻譯自:The calling thread cannot access this object because a different thread owns it

My code is as below 我的代碼如下

public CountryStandards()
{
    InitializeComponent();
    try
    {
        FillPageControls();
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message, "Country Standards", MessageBoxButton.OK, MessageBoxImage.Error);
    }
}

/// <summary>
/// Fills the page controls.
/// </summary>
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;

}

/// <summary>
/// Gets the grid data.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="pageIndex">Index of the page.( used in case of paging)   </pamam>
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);
    }
}

The step objUDMCountryStandards.Country = txtSearchCountry.Text.Trim() != string.Empty ? txtSearchCountry.Text : null; 步驟objUDMCountryStandards.Country = txtSearchCountry.Text.Trim() != string.Empty ? txtSearchCountry.Text : null; objUDMCountryStandards.Country = txtSearchCountry.Text.Trim() != string.Empty ? txtSearchCountry.Text : null; in get grid data throws exception 在獲取網格數據時拋出異常

The calling thread cannot access this object because a different thread owns it. 調用線程無法訪問該對象,因爲其他線程擁有它。

What's wrong here? 怎麼了


#1樓

參考:https://stackoom.com/question/epvB/調用線程無法訪問該對象-因爲其他線程擁有它


#2樓

您需要更新到用戶界面,因此請使用

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

#3樓

Another good use for Dispatcher.Invoke is for immediately updating the UI in a function that performs other tasks: Dispatcher.Invoke另一個好用法是立即執行執行其他任務的功能中的UI:

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

I use this to update button text to " Processing... " and disable it while making WebClient requests. 我使用它來將按鈕文本更新爲“正在處理... ”,並在發出WebClient請求時將其禁用。


#4樓

For some reason Candide's answer didn't build. 由於某種原因,Candide的答案沒有建立。 It was helpful, though, as it led me to find this, which worked perfectly: 但是,這很有幫助,因爲它使我找到了這個,它非常有效:

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

#5樓

To add my 2 cents, the exception can occur even if you call your code through System.Windows.Threading.Dispatcher.CurrentDispatcher.Invoke() . 要加2美分,即使您通過System.Windows.Threading.Dispatcher.CurrentDispatcher.Invoke()調用代碼,也會發生異常。
The point is that you have to call Invoke() of the Dispatcher of the control that you're trying to access , which in some cases may not be the same as System.Windows.Threading.Dispatcher.CurrentDispatcher . 關鍵是您必須Invoke() 要訪問控件DispatcherInvoke() ,在某些情況下,它可能與System.Windows.Threading.Dispatcher.CurrentDispatcher So instead you should use YourControl.Dispatcher.Invoke() to be safe. 因此,相反,您應該使用YourControl.Dispatcher.Invoke()是安全的。 I was banging my head for a couple of hours before I realized this. 在意識到這一點之前,我敲了幾個小時。

Update 更新資料

For future readers, it looks like this has changed in the newer versions of .NET (4.0 and above). 對於未來的讀者來說,.NET的新版本(4.0及更高版本)似乎已發生了變化。 Now you no longer have to worry about the correct dispatcher when updating UI-backing properties in your VM. 現在,在更新VM中的UI支持屬性時,您不再需要擔心正確的調度程序。 WPF engine will marshal cross-thread calls on the correct UI thread. WPF引擎將在正確的UI線程上封送跨線程調用。 See more details here . 在這裏查看更多詳細信息。 Thanks to @aaronburro for the info and link. 感謝@aaronburro提供的信息和鏈接。 You may also want to read our conversation below in comments. 您可能還想閱讀下面的評論我們的對話。


#6樓

If you encounter this problem and UI Controls were created on a separate worker thread when working with BitmapSource or ImageSource in WPF, call Freeze() method first before passing the BitmapSource or ImageSource as a parameter to any method. 如果您遇到此問題,並且在WPF中使用BitmapSourceImageSource單獨的工作線程上創建了UI控件,請先調用Freeze()方法,然後再將BitmapSourceImageSource作爲參數傳遞給任何方法。 Using Application.Current.Dispatcher.Invoke() does not work in such instances 在這種情況下,無法使用Application.Current.Dispatcher.Invoke()

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章