c# - Application.ThreadException 事件未捕获绑定(bind)属性的 Set 方法中的异常

标签 c# .net data-binding exception

看来,属性的 Set 方法中发生的异常不会引发到应用程序的 ThreadException 事件。

我们将该事件与 AppDomain.CurrentDomain.UnhandledException 事件一起使用来捕获应用程序中发生的任何意外事故。异常详细信息将写入日志,以便我们的支持和开发团队可以更好地评估问题。遗憾的是,在这种特殊情况下,Catch All 看起来似乎不够。

StackOverflow 上有几个类似的问题,但没有答案解决全局异常处理未捕获异常的问题。我已经知道我们可以修复它,所以不会发生异常。我们可以向每个 setter 添加一个 TryCatch block 。我们可以将 BindingComplete 事件添加到每个数据绑定(bind)并以这种方式获取异常。但所有这些都违背了全局异常处理的目的,而全局异常处理在任何其他情况下都可以完美地工作。

要重现该问题,只需创建一个带有文本框的表单,将文本框绑定(bind)到属性并在属性的 set 方法中抛出异常。将 ThreadException 和 UnhandledException 事件添加到program.cs。运行程序并在文本框中键入以触发异常。调试器将在异常发生时中断,按“继续”(F5),让异常像在调试器外部一样冒泡。任何正常的异常都会在这些事件中结束,但这个事件不会。

Form1.cs

    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        textBox1.DataBindings.Add("Text", this, "TestValue", true, DataSourceUpdateMode.OnPropertyChanged);            
    }

    private string _TestValue = "";
    public string TestValue
    {
        get{return _TestValue;}
        set
        {
            _TestValue = value;
            throw new Exception("Something bad happened in here");
        }
    }

Program.cs

static class Program
{
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

        Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
        Application.ThreadException += ThreadExceptionHandler;
        AppDomain.CurrentDomain.UnhandledException += new System.UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
        TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;

        Application.Run(new Form1());
    }

    private static void ThreadExceptionHandler(object sender, System.Threading.ThreadExceptionEventArgs args)
    {
        try
        {
            //RR.Common.ErrorLogRt.WriteError(args.Exception.StackTrace.ToString(), args.Exception.Message.ToString(), true);
            MessageBox.Show(args.Exception.Message);
        }
        catch
        {
            MessageBox.Show("Error writing to exception log. This program will now terminate abnormally.");
            Application.Exit();
        }
    }

static void CurrentDomain_UnhandledException(object sender, System.UnhandledExceptionEventArgs e)
    {
        try
        {
            if (e != null)
            {
                Exception ex = e.ExceptionObject as Exception;
                //RR.Common.ErrorLogRt.WriteError(ex.StackTrace.ToString(), ex.Message.ToString(), true);
                MessageBox.Show(ex.Message);
            }
            else
            {
                MessageBox.Show("Unhandled Error: " + e.ToString());
            }
        }
        catch
        {
            MessageBox.Show("Error writing to exception log. This program will now terminate abnormally.");
            Application.Exit();
        }
    }


 static void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
    {
        try
        {
            if (e != null && e.Exception != null && e.Exception.InnerException != null)
            {
                //The unobserved exception is always the same, The actual exception that cause it will be the inner exception.
                Exception ex = e.Exception.InnerException;
                MessageBox.Show(e.Exception.Message);
                //RR.Common.ErrorLogRt.WriteError(ex.StackTrace.ToString(), ex.Message.ToString(), true);
            }
            else
            {
                MessageBox.Show("Unhandled Error: " + e.ToString());
            }


        }
        catch
        {
            MessageBox.Show("Error writing to exception log. This program will now terminate abnormally.");
            Application.Exit();
        }
    }



}

最佳答案

Remarks from Binding.FormattingEnabled Property

Setting this property to true also enables error-handling behavior and causes the BindingComplete event to be raised. The handler of this event can take the appropriate action, based on the success, error, or exceptions in the binding process, by examining the BindingCompleteState property of the BindingCompleteEventArgs parameter.

The code involved

internal bool PushData(bool force)
{
    Exception ex = null;
    if (!force && this.ControlUpdateMode == ControlUpdateMode.Never)
    {
        return false;
    }
    if (this.inPushOrPull && this.formattingEnabled)
    {
        return false;
    }
    this.inPushOrPull = true;
    try
    {
        if (this.IsBinding)
        {
            object value = this.bindToObject.GetValue();
            object propValue = this.FormatObject(value);
            this.SetPropValue(propValue);
            this.modified = false;
        }
        else
        {
            this.SetPropValue(null);
        }
    }
    catch (Exception ex2)
    {
        ex = ex2;
        if (!this.FormattingEnabled)
        {
            throw;
        }
    }
    finally
    {
        this.inPushOrPull = false;
    }
    if (this.FormattingEnabled)
    {
        BindingCompleteEventArgs bindingCompleteEventArgs = this.CreateBindingCompleteEventArgs(BindingCompleteContext.ControlUpdate, ex);
        this.OnBindingComplete(bindingCompleteEventArgs);
        return bindingCompleteEventArgs.Cancel;
    }
    return false;
}

如您所见,将第四个参数传递为 true:DataBindings.Add("Text", this, "TestValue", true 负责捕获 PushData 内的异常> 并将其传递给 BindingComplete 事件。除 BindingComplete 之外,没有其他方法(除了 AppDomain.CurrentDomain.FirstChanceException)可以在其他任何地方找到异常> 如果启用了格式设置。

关于c# - Application.ThreadException 事件未捕获绑定(bind)属性的 Set 方法中的异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24702330/

相关文章:

c# - EF 同一主键上的多个外键关系

c# - Winforms 最小化技术

c# - 将动态对象解析委托(delegate)给其他实例

c# - 我的 BackgroundWorker 实例何时会被垃圾回收

c# - CaSTLe Windsor - 一个接口(interface)的多重实现

c# - 如何更新 EF 6 中的外键 - Code First - 一对多关系

c# - 异步添加到 ObservableCollection(或替代方案)

silverlight - 这个绑定(bind)语法有什么问题: {Binding List[Index]}?

c# - 如何从 View 模型更新 View 中的单选按钮?

c# - oracle 参数化查询 - 如何更改/删除/修改参数