我的代码如下

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

该步骤遵循judmcountrystandards。Country = txtSearchCountry.Text.Trim() !=字符串。空的吗?txtSearchCountry。文本:null;在获取网格数据时抛出异常

调用线程不能访问此对象,因为有不同的 线程拥有它。

这里出了什么问题?


当前回答

你需要在UI线程上做。使用:

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

其他回答

有时,抛出异常的可能是您创建的对象,而不是我明显看到的目标。

在我的代码中:

xaml文件:

<Grid Margin="0,0,0,0" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" >
    <TextBlock x:Name="tbScreenLog" VerticalAlignment="Stretch" Background="Black" FontSize="12" Foreground="#FF919191" HorizontalAlignment="Stretch"/>
</Grid>

xaml.cs文件:

System.Windows.Documents.Run rnLine = new System.Windows.Documents.Run(Message.Item2 + "\r\n");
rnLine.Foreground = LineAlternate ? Brushes.Green : Brushes.Orange;

Dispatcher.Invoke(()=> {
    tbScreenLog.Inlines.Add(rnLine);
});
LineAlternate = !LineAlternate;

我得到了关于从不同线程访问对象的异常,但我在UI线程上调用它??

过了一段时间,它吓倒了我,这不是关于TextBlock对象,而是关于运行对象我创建之前调用。

把代码改成这样就解决了我的问题:

Dispatcher.Invoke(()=> {
    Run rnLine = new Run(Message.Item2 + "\r\n");
    rnLine.Foreground = LineAlternate ? Brushes.Green : Brushes.Orange;
    tbScreenLog.Inlines.Add(rnLine);
});
LineAlternate = !LineAlternate;

出于某种原因,坎迪德的回答并不可信。尽管如此,它还是很有帮助的,因为它让我发现了这个,它非常有效:

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

另外,另一个解决方案是确保控件是在UI线程中创建的,而不是由后台工作线程创建的。

我还发现System.Windows.Threading.Dispatcher.CurrentDispatcher.Invoke()并不总是目标控制的调度程序,就像dotNet在他的回答中所写的那样。我没有访问控件自己的调度程序,所以我使用Application.Current.Dispatcher,它解决了这个问题。

补充一点,即使你通过System.Windows.Threading.Dispatcher.CurrentDispatcher.Invoke()调用你的代码,也会发生异常。关键是你必须调用你试图访问的控件的Dispatcher的Invoke(),在某些情况下可能与System.Windows.Threading.Dispatcher.CurrentDispatcher不相同。因此,为了安全起见,您应该使用YourControl.Dispatcher.Invoke()。我敲了几个小时的头才意识到这一点。

更新

对于未来的读者来说,这一点在。net的新版本(4.0及以上版本)中似乎有所改变。现在,在VM中更新ui支持属性时,您不再需要担心正确的调度程序。WPF引擎将在正确的UI线程上编组跨线程调用。点击这里查看更多细节。感谢@aaronburro提供的信息和链接。你也可以在评论中阅读我们的对话。

更新2

Since this is a popular post now, I thought I'd share my experience that I had in the following years. The behavior seems to be that any property bindings will update correctly in cross-thread calls (no marshalling required; WPF will handle it for you). OTOH command bindings will need to be delegated to the UI dispatcher. I have tested it with both MVVM Light and the relatively new Community Toolkit and it seems to be the case with both the old Framework and the new .NET 5 and 6. AsyncRelayCommand fails to update the UI when invoked from non-UI thread (This happens when CanExecuteChanged is fired from a worker thread which updates, for example, button's Enabled property). The solution of course is to store UI dispatcher somewhere in the global space in your VM upon startup and then use it when updating the UI.