问题
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