2017-08-06 67 views
1

尝试隔离问题时尽可能简化了此问题。我假设它与单独线程中引发的异常有关由Timer.Elapsed引发的异常未被尝试的全局异常事件处理程序捕获Visual C#

让我们来看看WindowsFormApp。

设程序类源看起来像这样

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()有一个覆盖。这些方法用作未处理线程异常的事件处理程序,以及来自主线程的未处理异常。 (如果这不正确,我想纠正这一点,但这是我的理解)。

假设在主形式中,当一个按钮被点击则抛出异常

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线程?

任何/所有输入赞赏。

+3

这是'System.Timers.Timer'的一个已知问题 - 定时器回调中的任何未处理的异常都被框架吞噬。 *始终*在'System.Timers.Timer'回调提供自己的异常处理程序。或者,确实不要使用'System.Timers.Timer'。如果你打算为'System.Threading.Timer',知道的[分歧](https://stackoverflow.com/q/1416803/)。 –

+0

有没有你不使用'System.Windows.Forms.Timer'一个原因? – lesscode

+2

你也可以设置'SynchronizingObject'您当前的定时器(也许)你'Form'对象。那么这将调用UI线程上的回调和异常不会被吞噬。 – lesscode

回答

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

当经过事件是由视觉的Windows窗体处理组件,作为一个按钮这样 ,通过系统线程池 可能导致异常或只是可能无法正常工作访问该组件。通过设置SynchronizingObject的到Windows避免这种 效果窗体组件, 引起该处理上 被称为经过的事件在同一线程该组件创建的方法。 - Microsoft.Com