[C#][VB.NET]自定義例外對話框

  • 18179
  • 0
  • 2010-07-18

[C#][VB.NET]自定義例外對話框

之前在『例外處理使用時機』這篇有提到我目前很少會寫例外處理。除了在那篇提到的原因之外,還有個因素就是我會弄個自定義的例外處理視窗,讓使用者在例外發生時,可以匯出例外訊息並提供給開發人員。有了匯出的例外訊息,我們就可以很快的把未處理完的例外(指給程式員看的例外)給修正。

要做到自定義的例外對話框,我們需要利用Application.ThreadException事件。

先讓我們看一下MSDN的說明:

image

 

從MSDN的說明可以很清楚的看到,當執行緒發生例外,且該例外未被處理,則該事件即會觸發。

 

接著就讓我們來看看如何才能利用該事件做出自定義的例外對話框。首先,我們需要設計自定義的例外對話框。

image

 

接著撰寫繫上事件用的副程式。

VB.NET

    Public Shared Sub ShowBugWindowOnError()
        AddHandler Application.ThreadException, AddressOf OnErrorOccur
    End Sub

 

C#

    public static void ShowBugWindowOnError()
    {
        Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(OnErrorOccur);
    }   

 

 

最後寫上事件觸發時要執行的事件處理函式。

VB.NET

    Protected Shared Sub OnErrorOccur(ByVal sender As Object, ByVal e As ThreadExceptionEventArgs)
        Dim errorDlg As New ExceptionDialog
        errorDlg.DetailErrorMsg_TextBox.Text = GetDetailErrorMsg(e.Exception)
        errorDlg.ShowDialog()
    End Sub

 

C#

    protected static void OnErrorOccur(object sender, System.Threading.ThreadExceptionEventArgs e)
    {
        ExceptionDlg errorDlg = new ExceptionDlg();
        errorDlg.DetailErrorMsg_TextBox.Text = GetDetailErrorMsg(e.Exception);
        errorDlg.ShowDialog();
    }

 

 

到此一個簡單的自定義例外對話框就完成了。使用上,我們只需呼叫剛寫的繫上事件用副程式即可。

VB.NET

   Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        ExceptionDialog.ShowBugWindowOnError()
    End Sub

C#

    private void Form1_Load(object sender, EventArgs e)
    {
        ExceptionDlg.ShowBugWindowOnError();
    }

 

 

完整程式碼:

VB.NET

Imports System.Windows.Forms
Imports System.Threading
Imports System.Text
 
Public Class ExceptionDialog
 
#Region "Const"
    Const OpenDetailButtonText As String = "v 詳細資料"
    Const CloseDetailButtonText As String = "^ 詳細資料"
#End Region
 
 
 
#Region "Var"
    Private _isDetailOpened As Boolean
#End Region
 
 
 
#Region "Public Shared Method"
 
    '***************************************************************************
    'Author: Larry Nung
    'Date: 2009/4/9
    'Purpose: 
    'Memo: 
    '***************************************************************************
    ''' <summary>
    ''' Shows the bug window on error.
    ''' </summary>
    ''' <remarks></remarks>
    Public Shared Sub ShowBugWindowOnError()
        AddHandler Application.ThreadException, AddressOf OnErrorOccur
    End Sub
#End Region
 
 
#Region "Protected Shared Method"
 
    '***************************************************************************
    'Author: Larry Nung
    'Date: 2009/4/9
    'Purpose: 
    'Memo: 
    '***************************************************************************
    ''' <summary>
    ''' Called when [error occur].
    ''' </summary>
    ''' <param name="sender">The sender.</param>
    ''' <param name="e">The <see cref="System.Threading.ThreadExceptionEventArgs" /> instance containing the event data.</param>
    ''' <remarks></remarks>
    Protected Shared Sub OnErrorOccur(ByVal sender As Object, ByVal e As ThreadExceptionEventArgs)
        Dim errorDlg As New ExceptionDialog
        errorDlg.DetailErrorMsg_TextBox.Text = GetDetailErrorMsg(e.Exception)
        errorDlg.ShowDialog()
    End Sub
#End Region
 
 
#Region "Private Shared Method"
 
    '***************************************************************************
    'Author: Larry Nung
    'Date: 2009/4/9
    'Purpose: 
    'Memo: 
    '***************************************************************************
    ''' <summary>
    ''' Gets the detail error MSG.
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Shared Function GetDetailErrorMsg(ByVal e As Exception) As String
        Dim str As New StringBuilder
        str.AppendLine(String.Format("Source: {0}", e.Source))
        str.AppendLine(String.Format("Message: {0}", e.Message))
        str.AppendLine(String.Format("TargetSite: {0}", e.TargetSite))
        str.AppendLine("")
        str.AppendLine("StackTrace: ")
        str.AppendLine(e.StackTrace)
        Return str.ToString
    End Function
#End Region
 
 
 
 
 
#Region "Event Process"
    Private Sub OK_Button_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles OK_Button.Click
        Me.DialogResult = System.Windows.Forms.DialogResult.OK
        Me.Close()
    End Sub
 
    Private Sub Cancel_Button_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Cancel_Button.Click
        Me.DialogResult = System.Windows.Forms.DialogResult.Cancel
        Application.Exit()
    End Sub
 
    Private Sub Detail_Button_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Detail_Button.Click
        _isDetailOpened = Not _isDetailOpened
        Detail_Button.Text = If(_isDetailOpened, CloseDetailButtonText, OpenDetailButtonText)
        Me.Height = If(_isDetailOpened, Me.DetailErrorMsg_TextBox.Bottom, Me.DetailErrorMsg_TextBox.Top) + 32
    End Sub
 
    Private Sub ExceptionDialog_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Me.Height = Me.DetailErrorMsg_TextBox.Top + 32
        Me.ErrorIcon_Label.Image = SystemIcons.Error.ToBitmap
    End Sub
#End Region
 
End Class

C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
 
 
namespace ExceptionDlgTest
{
    public partial class ExceptionDlg : Form
    {
 
        #region Const
        const string OpenDetailButtonText = "v 詳細資料";
        const string CloseDetailButtonText = "^ 詳細資料";
        #endregion
 
        #region Var
        private Boolean _isDetailOpened;
        #endregion
 
 
        #region Construction
        public ExceptionDlg()
        {
            InitializeComponent();
        }
        #endregion
 
 
 
        #region Public Shared Method
 
        //***************************************************************************
        //Author: Larry Nung
        //Date: 2009/4/9
        //Purpose: 
        //Memo: 
        //***************************************************************************
        /// <summary>
        /// 
        /// </summary>
        public static void ShowBugWindowOnError()
        {
            Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(OnErrorOccur);
        }     
        #endregion
 
 
        #region Protected Shared Method
        protected static void OnErrorOccur(object sender, System.Threading.ThreadExceptionEventArgs e)
        {
            ExceptionDlg errorDlg = new ExceptionDlg();
            errorDlg.DetailErrorMsg_TextBox.Text = GetDetailErrorMsg(e.Exception);
            errorDlg.ShowDialog();
        }
        #endregion
 
 
        #region Private Shared Method
        private static string GetDetailErrorMsg(Exception e)
        {
            StringBuilder str = new StringBuilder();
            str.AppendLine(String.Format("Source: {0}", e.Source));
            str.AppendLine(String.Format("Message: {0}", e.Message));
            str.AppendLine(String.Format("TargetSite: {0}", e.TargetSite));
            str.AppendLine("");
            str.AppendLine("StackTrace: ");
            str.AppendLine(e.StackTrace);
            return str.ToString();
        }
        #endregion
 
 
        #region Event Process
        private void Cancel_Button_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }
 
        private void OK_Button_Click(object sender, EventArgs e)
        {
            this.Close();
        }
 
        private void Detail_Button_Click(object sender, EventArgs e)
        {
            _isDetailOpened = !_isDetailOpened;
            Detail_Button.Text = _isDetailOpened ? CloseDetailButtonText : OpenDetailButtonText;
            this.Height = _isDetailOpened ? this.DetailErrorMsg_TextBox.Bottom : this.DetailErrorMsg_TextBox.Top + 32;
        }
 
        private void ExceptionDlg_Load(object sender, EventArgs e)
        {
            this.Height = this.DetailErrorMsg_TextBox.Top + 32;
            this.ErrorIcon_Label.Image = SystemIcons.Error.ToBitmap();
        }
        #endregion
 
     
    }
}

 

 

執行畫面如下:

image

image

 

Conclusion

透過Application.ThreadException事件,我們可以很容易達到該篇的效果。但需注意這樣的作法只對繫上的執行緒有效,非繫上的執行緒若發生例外,將無法截取到。在實際應用上,也可依自己需求加入記錄到事件記錄簿等功能,甚至可以使用.NET預設的例外視窗來顯示,只是多加了一些自己的處理,讓使用者感覺不出差異。

        AddHandler Application.ThreadException, AddressOf Application_ThreadException
        ...
    End Sub

    Private Sub Application_ThreadException(ByVal sender As Object, ByVal e As ThreadExceptionEventArgs)
        ... 
        Dim exceptionDlg As New ThreadExceptionDialog(e.Exception)
        exceptionDlg.ShowDialog()
    End Sub

image

 

另外,若有興趣的也可以改繫上AppDomain.UnhandledException試看看。

image 

 

Download

ExceptionDlg.zip