iT邦幫忙

DAY 26
2

程式設計心法系列 第 26

程式設計心法:25.實作 Form 的繼承(上)

終於,我們要真正開始寫程式了。

這一篇分上下兩集,要介紹的是如何實作 Form 的繼承物件,這是在 2006 年
發表在自己的 Blog 上面的,原文請參考:
http://jamesjantw.blogspot.com/2006/09/net-windows-form.html

茲節錄部分文字,以作為說明

緣起:

之前在 VB6 的時代,常常會撰寫一些排程的程式去執行一些 Backend 的作業(當然你也可以用 OS 的 Schedule 來排程)。每次需要新的作業時都是將程式目錄 Copy 一遍再逐一去改命名,雖然自己已經有一些開發的 Pattern(ini 檔、log 檔、Error 發送 email 通知開發者),開發速度上也很快,但是如果我要讓所有的程式都增加一個新的功能,這樣我得為每一個專案加入這個功能,為數眾多時這可是頗耗時間的。

以前開發 Delphi (3.0) 時,就已經有 Form 繼承的作法了,程式模組可以重複使用,那為什麼同性質的 Form 不可以呢?基於這樣的需求,所以決定第一支程式以 Windows Form 繼承實作做為開端。

思考:

1.哪些功能該擺在 BaseForm 上?Inheritance consideration
2.如何擴充已有的功能?Overrides
3.如何讓同一功能具備多樣性?Overloads
4.應用程式設定檔
5.應用程式記錄檔
6.Exception Notification(通知錯誤訊息 & 出錯行號)
好吧,我們就來試做看看!
首先,開啟一個 Visual Studio 專案,選擇「類別庫」(Class Library)(程式當時是使用 .Net 2.0 的環境,抓圖片時沒有變更。)
Project

我們使用到三個類別,如下圖所示:(當然這是完成圖)
CLass Diagram

接下來,先拉好一個 Form,將我們要的元件擺上去。
這個程式是用來作自動執行小程式的範本,我現在有需要排程做運算的程式,都使用他作為
Parent Form 來繼承,我只要將要執行的程式碼加上去,就變成一個新程式了,一些
Error Handling 啦,Log 啦都自動有了,我也不用去另外設計 Form。

BaseForm

底下是程式碼的內容,我們在 Base Form Class 上,又宣告了兩個物件,Log 跟 Send Mail
他們主要是用來作 Error Handling 與錯誤通知用的。

BaseForm.vb

Public Class BaseForm
  Protected RunTimer As Integer
  Protected sendmail As SendMail
  Protected log As Log

  Private Sub BaseForm_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
    mnuSwitch.Text = "離開"
    mnuSwitch_Click(sender, e)
  End Sub

  Private Sub BaseForm_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    sendmail = New SendMail()
    log = New Log()
    Timer1.Enabled = True
    ShowTimer()
  End Sub

  Private Sub ShowTimer()
    ToolStripStatusLabel2.Text = Now().ToString
  End Sub

  Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
    ShowTimer()
  End Sub

  Private Sub mnuSwitch_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuSwitch.Click
    Timer2.Enabled = mnuSwitch.Text.Equals("啟動")
    ListBox1.Items.Add(Now().ToString & " " & mnuSwitch.Text)
    log.Writeln(mnuSwitch.Text, TraceEventType.Information)
    mnuSwitch.Text = IIf(mnuSwitch.Text.Equals("啟動"), "停止", "啟動")
  End Sub

  Protected Sub ExceptionHandler(ByVal ex As Exception, ByVal ErrorMessage As String)
    My.Application.Log.WriteException(ex, _
      TraceEventType.Error, _
      Now().ToString)
    sendmail.Message.Subject = ErrorMessage
    sendmail.Message.Body = "Message ---" & vbCrLf & ex.Message & vbCrLf & vbCrLf & _
                            "Source ---" & vbCrLf & ex.Source & vbCrLf & vbCrLf & _
                            "StackTrace ---" & vbCrLf & ex.StackTrace & vbCrLf & vbCrLf & _
                            "TargetSite ---" & vbCrLf & ex.TargetSite.ToString()

    sendmail.Send()
  End Sub
End Class

程式碼大多都是將元件的動作 define 好,最重要的就是最下面的 ExceptionHandler()
他會將錯誤寫到 Log File(相關設定下篇再說明)以及發送 mail 通知。

如果您眼尖一點,可以發現,SendMail 並沒有指定 Form、To以及 SMTP Host!這是因為在 Base Form 上不應該指定這些,因為那是給實際執行的程式去設定的!所以在繼承的程式中,要去指定這幾個屬性。

Log.vb

Public Class Log

  Public Sub New()
  End Sub

  Public Sub Writeln(ByVal strLog As String, ByVal TraceEvent As Integer)

    Try
      Application.DoEvents()
      My.Application.Log.WriteEntry(strLog & vbTab & Now().ToString, TraceEvent)
    Catch ex As IO.IOException
      My.Application.Log.WriteException(ex, _
            TraceEventType.Error, _
            Now().ToString)
    End Try
  End Sub
End Class

這是讓程式除了將 Exception 寫入 Log 之外,程式也可以將執行過程記錄下來的用法。

SendMail.vb

Imports System.Net.Mail.SmtpClient
Imports System.Net.Mail.MailMessage

Public Class SendMail
  Public Message As System.Net.Mail.MailMessage
  Public SmtpClient As System.Net.Mail.SmtpClient

  Public Sub New(ByVal host As String)
    SmtpClient = New System.Net.Mail.SmtpClient(host)
    Message = New System.Net.Mail.MailMessage()
  End Sub

  Public Sub New()
    SmtpClient = New System.Net.Mail.SmtpClient()
    Message = New System.Net.Mail.MailMessage()
  End Sub

  Public Sub Send()
    If Not IsNothing(SmtpClient.Host) And Not IsNothing(Message.From) And Not IsNothing(Message.To) Then
      SmtpClient.Send(Message)
    End If
  End Sub
End Class

在這裡,我們對 SendMail 的 Constructor 做 Overloadding,一個有提供 host,一個沒有。這樣做是為了讓程式不會出錯。同時我們在 Send 的動作中,有做 Host 跟 From、To 的判斷這樣可確保都有指定了才送信。

好了這些設定完之後,我們就可以建置專案,產生 TimerBaseFormLibrary.dll,這個檔案就是
我們的核心,他是可以帶著走的,在別台機器只要將他註冊就可以使用。(regsvr32 TimerBaseFormLibrary.dll)

本系列文章


上一篇
程式設計心法:24.練習曲
下一篇
程式設計心法:26.實作 Form 的繼承(下)
系列文
程式設計心法31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言