WPF Dispatcher.BeginInvoke抛出异常

时间:2012-10-24 08:36:30

标签: wpf multithreading

我正在使用Threadpool.QueueUserWorkItem,如下面的

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

通过这种方式,TestMain()无法捕获异常。 程序将关闭......

我怎样才能发现这个错误?

THX。

6 个答案:

答案 0 :(得分:1)

原因是this.Dispatcher.BeginInvoke(new Action(() => this.BackGroundMethod));异步执行,因此它会在执行TestMain之前完成执行BackGroundMethod内的所有代码。

答案 1 :(得分:1)

使用Dispatcher.UnhandledException事件来捕获TestMain()方法中的异常,如下所示:

Dispatcher.UnhandledException += (sender, args) => MessageBox.Show(args.Exception.Message);
ThreadPool.QueueUserWorkItem(ignore => Dispatcher.Invoke(new Action(BackGroundMethod)));

编辑:请记住设置Handled属性以防止调用内部异常处理程序:

Dispatcher.UnhandledException += (sender, args) => 
{
    MessageBox.Show(args.Exception.Message);
    args.Handled = true;
}

答案 2 :(得分:0)

当您使用Dispatcher创建一个新线程时,该线程拥有它自己的堆栈,因此异常不会传递给TestMain中的try ... catch,而是它们将来自{{1 }} 方法。当您在BackgroundMethod中抛出异常时,try catch是无用的,因此如果您不在BackgroundMethod中抛出异常,则程序将无法关闭。

BackgroundMethod

答案 3 :(得分:0)

您可以通过处理AppDomain.UnhandledException

来捕获应用程序中所有线程中的所有异常

答案 4 :(得分:0)

为防止崩溃,请在可能抛出的操作周围添加try / catch

ThreadPool.QueueUserWorkItem(x =>
{
    try {
        this.Dispatcher.BeginInvoke(new Action(() => this.BackGroundMethod()));
    }
    catch (DivideByZeroException ex) {
        // handle the error somehow
    }
});

但是,请考虑一下您在这里做了什么:您正在向线程池推送一些操作,然后将相同的操作推送到调度程序线程。如果没有QueueUserWorkItem电话,为什么不直接自己做?

答案 5 :(得分:0)

您可以通过捕获BeginInvoke函数中的异常并将其保存在临时变量中来完成此操作。在等待之后,您可以在正确的线程上重新抛出它。

           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