在前篇,我們將 Parent Form 實作出來了。接下來,我們要藉由 TimerBaseFormLibrary
來產生應用程式。
這裡沒有很高深的理論架構, 只是運用物件導向中很基本的「繼承」、「多型」等技巧。.Net Framework 內建的 Application log 機制則具備有多樣的選擇, 你可以很容易的將程式執行的過程所產生的訊息紀錄到 log 檔 Application Event 或 XML 檔案等(在 app.config 中設定)
逐步解說:判斷 My.Application.Log 寫入資訊的位置
HOW TO:在 Visual Basic 中記錄例外狀況
但是 Exception Notification 的部份只能透過自己撰寫的方式來達成需 Import System.Net.Mail.SmtpClient & System.Net.Mail.MailMessage 這部份或許微軟應該把他考慮進來, 也透過 Config 的方式來達成。
好了,我們繼續繼承的開發實作吧!
首先,我們開啟一個新專案,這次選 Windows Form 專案
我們在專案中加入 Form,切換到 Widnows Form 選取「繼承表單」
建立好 Form 之後,我們先來看一下 Class Diagram 中有什麼變化?
好神奇喔!自動幫我們產生繼承的 Class Diagram 而且屬性也都清楚的標示出來。您也可以發現,繼承下來的元件不能刪除,但是可以再加上這個 Form 自己的元件上去。
接下來,我們在 Form2.vb 中撰寫程式碼
Public Class Form2
Private Sub Timer2_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer2.Tick
If RunTimer >= My.Settings.RunTimer Then
ToolStripStatusLabel1.Text = "Next Time:" & Now().AddSeconds(My.Settings.RunTimer).ToString
ListBox1.Items.Add(Now().ToString & " Form2")
RunTimer = 1
doCheck()
Else
RunTimer += 1
End If
End Sub
Private Sub Form2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
sendmail.SmtpClient.Host = My.Settings.SMTP
sendmail.Message.From = New System.Net.Mail.MailAddress(My.Settings.From)
sendmail.Message.To.Add(My.Settings.Rcpt)
End Sub
Private Sub doCheck()
Dim a As Integer
Try
a = "ABC"
Catch ex As Exception
ExceptionHandler(ex, Application.ProductName & ":" & Me.Name & ":doCheck")
End Try
End Sub
End Class
在 Form2_Load 中,我們將 sendmail 的值給指定好,同時使用了設定檔來記錄我們的設定在 .Net 中,這是很進步的作法,透過 My 這個 Name Space 真的幫我們節省掉不少工作。
我們在 Parent Form 上沒有 implement Timer2_Tick() 這個 Method,我們在這邊撰寫(如果 Parent Form 上有 Implement,那麼會 Override 掉父表單的 Timer2_Tick()),然後時間到了執行 doCheck 這個常式。在當中我們故意做了一個錯誤的設定,看會不會產生預期的結果。
我們可以看到在 C:\Temp\ 下產生了 InheritanceTest.log,
其內容記載如下:
DefaultSource Information 0 啟動 2009/10/30 下午 01:17:15
DefaultSource Error 2 從字串 "ABC" 至型別 'Integer' 的轉換是無效的。 2009/10/30 下午 01:18:19
DefaultSource Error 2 從字串 "ABC" 至型別 'Integer' 的轉換是無效的。 2009/10/30 下午 01:18:43
DefaultSource Information 0 離開 2009/10/30 下午 01:18:46
同時也發送 email 通知
剛剛我們是按了「啟動」鍵,讓程式執行的,如果要讓程式自動執行,我們在 Base Form 上有定義一個 mnuSwitch 的動作,只要在 Form2_Load 中加上:
MyBase.mnuSwitch.PerformClick()
就可以直接執行了。
OK, 那為什麼 log 會寫到 C:\Temp 這個路徑?
請在您的專案底下加入這一支程式:ApplicationEvents.vb
Namespace My
' MyApplication 可以使用下列事件:
'
' Startup: 在應用程式啟動時,但尚未建立啟動表單之前引發。
' Shutdown: 在所有應用程式表單關閉之後引發。如果應用程式不正常終止,就不會引發此事件。
' UnhandledException: 在應用程式發生未處理的例外狀況時引發。
' StartupNextInstance: 在啟動單一執行個體應用程式且應用程式已於使用中時引發。
' NetworkAvailabilityChanged: 在連接或中斷網路連接時引發。
Partial Friend Class MyApplication
Private Sub MyApplication_UnhandledException(ByVal sender As Object, ByVal e As Microsoft.VisualBasic.ApplicationServices.UnhandledExceptionEventArgs) Handles Me.UnhandledException
My.Application.Log.WriteException(e.Exception, _
TraceEventType.Critical, _
"Application shut down at " & _
My.Computer.Clock.GmtTime.ToString)
End Sub
End Class
End Namespace
他會在 My 這個 Name Space 中加入 MyApplication 這個 Exception Handling 機制(當時寫的時候是 Visual Studio 2005,不知道 2008 是否已內建?)
同時在 app.config 中要加入相關設定
<system.diagnostics>
<sources>
<!-- 這個區段定義 My.Application.Log 的記錄組態-->
<source name="DefaultSource" switchName="DefaultSwitch">
<listeners>
<add name="FileLog"/>
<add name="FileLogListener" />
</listeners>
</source>
</sources>
...
<sharedListeners>
<add name="FileLog"
type="Microsoft.VisualBasic.Logging.FileLogTraceListener, Microsoft.VisualBasic, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"
initializeData="FileLogWriter"/>
<add name="FileLogListener"
type="Microsoft.VisualBasic.Logging.FileLogTraceListener, Microsoft.VisualBasic, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
initializeData="FileLogListenerWriter"
location="Custom"
customlocation="c:\temp\" />
...
</sharedListeners>
</system.diagnostics>
這樣就會自動幫你產生 log 檔並對應到 Exception Handling 了。