在尝试隔离问题时,尽可能简化了此问题。我假设它与在单独的线程中引发的异常有关
让我们有一个WindowsFormApp。
假设Program类源看起来像这样
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(UnhandledExceptionOccurred);
Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(UnhandledExceptionOccurred);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
public static void UnhandledExceptionOccurred(object sender, UnhandledExceptionEventArgs e)
{
var x = (Exception)e.ExceptionObject;
MessageBox.Show("Unhandled Exception\r\n" + x.Message);
}
public static void UnhandledExceptionOccurred(object sender, ThreadExceptionEventArgs e_thread)
{
var x = e_thread.Exception;
MessageBox.Show("Thread Exception\r\n" + x.Message);
}
}
对不起,如果这已经是压倒性的。让我试着简化这篇文章中为了积累知识而发生的事情。
静态方法UnhandledExceptionOccurred()
有一个覆盖。这些方法用作Unhandled Thread Exceptions的事件处理程序,以及来自主线程的Unhandled Exceptions。 (如果这不正确,我想对此进行更正,但这是我理解的方式)。
假设在主窗体中,当单击按钮时会抛出异常
private void button1_Click(object sender, EventArgs e)
{
throw new Exception("Exception 1");
}
假设单击了该按钮。消息框读取
可以很好地捕获异常“线程异常异常1”
现在(差不多完成)假设在Form1的构造函数中,我创建了一个System.Timers.Timer
,间隔为5000毫秒,并为它的已事件事件提供了一个事件处理程序,它抛出异常。
System.Timers.Timer T;
public Form1()
{
InitializeComponent();
T = new System.Timers.Timer();
T.Interval = 5000; //Miliseconds;
T.Elapsed += new ElapsedEventHandler(TimerElapsed);
T.Start();
}
事件处理程序:
public void TimerElapsed(object sender, ElapsedEventArgs e)
{
T.Stop();
throw new Exception("Exception From Timer Elapsed");
}
现在假设表单已启动,并且通过了5秒。
不显示任何消息框,也不会弹出WindowsFormError框。程序默默地吞下异常,我可以点击之前提到的按钮,并使消息框像以前一样出现。
这里发生了什么?
我知道这很可能与计时器的线程有关。我已经搜索并搜索并且还没有找到一种方法来访问计时器正在使用的线程的内部,以便我可以为其UnhandledException和ThreadException事件添加一些事件处理程序。
也许我可以使用System.Threading.Timers Timer
。
我注意到这种类型的计时器的构造函数需要CallbackMethod
? (什么是回调方法?)也许这个回调方法可以用来将未处理的异常路由回MainUI线程?
感谢任何/所有输入。
答案 0 :(得分:1)
将System.Timers.Timer SyncronyzingObject设置为主窗体可以解决此问题。
System.Timers.Timer T;
public Form1()
{
InitializeComponent();
T = new System.Timers.Timer();
T.SynchronizingObject = this;
T.Interval = 5000; //Miliseconds;
T.Elapsed += new ElapsedEventHandler(TimerElapsed);
T.Start();
}
当Elapsed事件由可视Windows窗体组件处理时, 例如按钮,通过系统线程访问组件 池可能会导致异常或者可能无法正常工作。避免这样做 通过将SynchronizingObject设置为Windows窗体组件, 这会导致调用处理Elapsed事件的方法 创建组件的相同线程。 - Microsoft.Com