WPF:调用线程无法访问此对象,因为另一个线程拥有它

Bar*_*Lib 0 c# wpf multithreading

我知道有类似的问题,比如Here And Here,我看了他们一切,但他们似乎不适合我.

我有一个帖子:

private void Sample()
{
      Thread t = new Thread(new ThreadStart(Sample_Thread));
      t.SetApartmentState(ApartmentState.STA);
      t.Start();
}
Run Code Online (Sandbox Code Playgroud)

在Sample_Thread中,我之前调用过MessageBox哪个工作正常.

private void Sample_Thread()
{
     try{ ... }
     catch(Exception e)
     {
          MessageBox.Show("SampleText");
     }
}
Run Code Online (Sandbox Code Playgroud)

现在我尝试调用ModernDialog而不是MessageBox,它给了我错误,'The calling thread cannot access this object because a different thread owns it.' 所以我将我的代码更改为:

private void Sample_Thread()
{
     try{ ... }
     catch(Exception e)
     {
            Dispatcher.CurrentDispatcher.Invoke(() =>
            {
                ModernDialog.ShowMessage("SampleText");
            });
     }
}
Run Code Online (Sandbox Code Playgroud)

但是这仍然有同样的错误,我应该如何解决这个问题呢?谢谢!

Pan*_*vos 6

有很多重复,所有这些都有效,所有这些都是相同的:你无法从另一个线程修改UI.显示消息框修改UI.此限制适用于至少返回到Windows 95 其他操作系统(如Linux)的所有Windows版本.

您无需Invoke更新UI或原始线程以在后台执行任何操作..NET允许您在后台执行工作Task.Run,等待其结果并处理任何异常.你唯一需要写的是:

private void SomeMethod()
{
...
}

private async void myButton_Click(object sender, RoutedEventArgs e)
{
    try
    {
        await Task.Run(someMethod);
    }
    catch(Exception e)
    {
        ModernDialog.ShowMessage(e.ToString());
     }
}
Run Code Online (Sandbox Code Playgroud)

如果您想更新UI,而在后台处理,如显示进度,可以使用IProgress< T>这里解释的,使用任何类型的消息,如int,字符串或满级汇报:

private void SomeMethod(IProgress<string> progress)
{
   foreach(...)
   {
       progress.Report("foo");
       ....
   }
}

private async void myButton_Click(object sender, RoutedEventArgs e)
{
    var progressIndicator = new Progress<string>(reportProgressMethod);
    try
    {
        await Task.Run(()=>someMethod(progressIndicator());
    }
    catch(Exception e)
    {
        ModernDialog.ShowMessage(e.ToString());
    }
}
Run Code Online (Sandbox Code Playgroud)

async void应该只用于事件处理程序.在所有其他情况下,应该是不返回结果的异步方法的方法签名async Task