Reputation: 315
I am using Threadpool.QueueUserWorkItem like following
public void TestMain()
{
try
{
ThreadPool.QueueUserWorkItem(x =>
{
this.Dispatcher.BeginInvoke(new Action(() => this.BackGroundMethod()));
}
);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void BackGroundMethod()
{
try
{
int a = 0;
int b = 100;
var error = b / a;
}
catch(Exception)
{
throw;
}
}
By this way, TestMain() can not catch exception. Program will shut down...
How can i catch this error?
Thx.
Upvotes: 0
Views: 4887
Reputation: 246
You can do this by catching the exception in the BeginInvoke function and saving it in a temporary variable. After the await you can then rethrow it on the correct thread.
Exception thrown = null;
await Application.Current.Dispatcher.BeginInvoke(new Action<Action>(x =>
{
try
{
BackGroundMethod();
}
catch (Exception ex)
{
//exceptions on this thread MUST be caught or the program will exit
//we will save it, and then when we are back on the main thread we will rethrow it
thrown = ex;
}
}));
if (thrown != null)
throw thrown; //<--- I'm rethrowing it right here on the correct thread
Upvotes: 0
Reputation: 4922
When you use the Dispatcher to create a new thread, that thread has it's own stack, and so the exceptions wont bubble to the try...catch in TestMain
, but instead they will originate in BackgroundMethod
method. As you are throwing the exception in BackgroundMethod
your try catch is useless, and so if you were to not throw the exception in BackgroundMethod
your program wouldn't shut down.
private void BackGroundMethod()
{
try
{
int a = 0;
int b = 100;
var error = b / a;
}
catch(Exception)
{
MessageBox.Show(ex.Message);
}
}
Upvotes: 0
Reputation: 11896
You can catch all exceptions in all threads within the application by handling AppDomain.UnhandledException
Upvotes: 0
Reputation: 18102
Use Dispatcher.UnhandledException
event to catch the exception in the TestMain()
method like this:
Dispatcher.UnhandledException += (sender, args) => MessageBox.Show(args.Exception.Message);
ThreadPool.QueueUserWorkItem(ignore => Dispatcher.Invoke(new Action(BackGroundMethod)));
Edit: Remember to set the Handled
property to prevent the internal exception handler from being called:
Dispatcher.UnhandledException += (sender, args) =>
{
MessageBox.Show(args.Exception.Message);
args.Handled = true;
}
Upvotes: 1
Reputation: 437336
To prevent the crash, add a try
/catch
around the operation which might throw:
ThreadPool.QueueUserWorkItem(x =>
{
try {
this.Dispatcher.BeginInvoke(new Action(() => this.BackGroundMethod()));
}
catch (DivideByZeroException ex) {
// handle the error somehow
}
});
However, think about what you are doing here: you are pushing some action to the thread pool, and in turn it pushes the same action to the dispatcher thread. Why not do this yourself directly without the QueueUserWorkItem
call?
Upvotes: 0
Reputation: 5715
The reason is this.Dispatcher.BeginInvoke(new Action(() => this.BackGroundMethod));
executes asynchonously, so it will finished execute all code inside TestMain
before BackGroundMethod
is executed.
Upvotes: 1