WPF: The calling thread cannot access this object because a different thread owns it

假装没事ソ 提交于 2021-02-16 15:42:29

问题


I know there are similar questions like Here And Here, I looked them all, but they seems not work for me.

I have a thread:

private void Sample()
{
      Thread t = new Thread(new ThreadStart(Sample_Thread));
      t.SetApartmentState(ApartmentState.STA);
      t.Start();
}

In the Sample_Thread, I previously called MessageBox which works fine.

private void Sample_Thread()
{
     try{ ... }
     catch(Exception e)
     {
          MessageBox.Show("SampleText");
     }
}

Now I try to call ModernDialog instead of MessageBox, it gives me error 'The calling thread cannot access this object because a different thread owns it.' so I change my code to this:

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

But this still got that same error, how should I fix this? Thanks!


回答1:


There are a lot of duplicates, all of which work and all of which say the same thing: You can't modify the UI from another thread. Displaying a messagebox does modify the UI. This restriction applies to all versions of Windows going back at least to Windows 95 and other OSs like Linux.

You don't need Invoke to update the UI or raw threads to perform anything in the background either. .NET allows you to execute work in the background with Task.Run, await its result and handle any exceptions. The only thing you need to write is :

private void SomeMethod()
{
...
}

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

If you want to update the UI while processing in the background, eg to display progress, you can use the IProgress< T> as explained here, to report using any type as a message, eg int, string or a full class :

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

async void should only be used for event handlers. In all other cases, the method signature of an asynchronous method that doesn't return a result should be async Task



来源:https://stackoverflow.com/questions/45730765/wpf-the-calling-thread-cannot-access-this-object-because-a-different-thread-own

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!