VB.NET里面的Event机制(三)

现在我们看看这样一个问题。我们想要做这样一个控件,他继承自Window.Forms.TextBox下面,也就是说它支持TextBox的所有功能,但是我们需要一个新的功能,就是当用户按下回车之后,我们判断一下这个TextBox里面的文字,如果是空字符串的话,就显示一个MessageBox,默认的内容是“Empty connect is not validated.”。同时我们希望用户可以选择是否显示这个MessageBox。我们用此前的办法来做。

我们的类很快就可以完成。

Public Class MyTextBox

    Inherits TextBox

 

    Public Event EnterKeyPress(ByVal sender As Object, ByRef Cancel As Boolean, ByRef Message As String)

 

    Private Sub MyTextBox_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles MyBase.KeyPress

        'Do something then user press ENTER KEY

        If Asc(e.KeyChar) = 13 Then

            Dim Cancel As Boolean = False

            Dim Message As String = "Empty connect is not validated."

            'Send the event with parameters

            RaiseEvent EnterKeyPress(Me, Cancel, Message)

            'Show message box depend on the return parameters

            If Cancel = False Then

                MsgBox(Message)

            End If

        End If

    End Sub

 

End Class

而且我们很容易就可以使用这个控件了。

Public Class Form1

    Inherits System.Windows.Forms.Form

 

#Region " Windows Form Designer generated code "

 

    Public Sub New()

        MyBase.New()

 

        'This call is required by the Windows Form Designer.

        InitializeComponent()

 

        'Add any initialization after the InitializeComponent() call

 

    End Sub

 

    'Form overrides dispose to clean up the component list.

    Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)

        If disposing Then

            If Not (components Is Nothing) Then

                components.Dispose()

            End If

        End If

        MyBase.Dispose(disposing)

    End Sub

 

    'Required by the Windows Form Designer

    Private components As System.ComponentModel.IContainer

 

    'NOTE: The following procedure is required by the Windows Form Designer

    'It can be modified using the Windows Form Designer. 

    'Do not modify it using the code editor.

    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()

        '

        'Form1

        '

        Me.AutoScaleBaseSize = New System.Drawing.Size(5, 12)

        Me.ClientSize = New System.Drawing.Size(292, 273)

        Me.Name = "Form1"

        Me.Text = "Form1"

 

    End Sub

 

#End Region

 

    Friend WithEvents MyTextBox1 As New MyTextBox

 

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

        Me.Controls.Add(Me.MyTextBox1)

        Me.MyTextBox1.Location = New Point(100, 100)

    End Sub

 

    Private Sub MyTextBox1_EnterKeyPress(ByVal sender As Object, ByRef Cancel As Boolean, ByRef Message As String) Handles MyTextBox1.EnterKeyPress

 

    End Sub

 

End Class

现在看来一切正常,但是无聊的客户突然来了一个Mail,他们希望我们能够在显示MessageBox的时候,将TextBox的背景色变成红色,并且允许有可能在其它的时候会变成绿色。也就是说变色也是要使用者可以自由设定的。这样我们就要在Event参数列表里面加入一个新的背景色参数,并且修改所有使用了这个EventHandle函数。

Public Class MyTextBox

    Inherits TextBox

 

    Public Event EnterKeyPress(ByVal sender As Object, ByRef Cancel As Boolean, ByRef Message As String, ByVal BackColor As Color)

 

    Private Sub MyTextBox_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles MyBase.KeyPress

        'Do something then user press ENTER KEY

        If Asc(e.KeyChar) = 13 Then

            Dim Cancel As Boolean = False

            Dim Message As String = "Empty connect is not validated."

            Dim Color As Color = Color.Red

            'Send the event with parameters

            RaiseEvent EnterKeyPress(Me, Cancel, Message, Color)

            'Show message box depend on the return parameters

            If Cancel = False Then

                MsgBox(Message)

            End If

        End If

    End Sub

 

End Class

然后修改使用的地方,也许实际上我们只是让它显示成默认的红色,我们也需要修改使用Event的地方,因为Event的定义已经不同了。

Public Class Form1

    Inherits System.Windows.Forms.Form

 

#Region " Windows Form Designer generated code "

 

    Public Sub New()

        MyBase.New()

 

        'This call is required by the Windows Form Designer.

        InitializeComponent()

 

        'Add any initialization after the InitializeComponent() call

 

    End Sub

 

    'Form overrides dispose to clean up the component list.

    Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)

        If disposing Then

            If Not (components Is Nothing) Then

                components.Dispose()

            End If

        End If

        MyBase.Dispose(disposing)

    End Sub

 

    'Required by the Windows Form Designer

    Private components As System.ComponentModel.IContainer

 

    'NOTE: The following procedure is required by the Windows Form Designer

    'It can be modified using the Windows Form Designer. 

    'Do not modify it using the code editor.

    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()

        '

        'Form1

        '

        Me.AutoScaleBaseSize = New System.Drawing.Size(5, 12)

        Me.ClientSize = New System.Drawing.Size(292, 273)

        Me.Name = "Form1"

        Me.Text = "Form1"

 

    End Sub

 

#End Region

 

    Friend WithEvents MyTextBox1 As New MyTextBox

 

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

        Me.Controls.Add(Me.MyTextBox1)

        Me.MyTextBox1.Location = New Point(100, 100)

    End Sub

 

    Private Sub MyTextBox1_EnterKeyPress(ByVal sender As Object, ByRef Cancel As Boolean, ByRef Message As String, ByVal Color As Color) Handles MyTextBox1.EnterKeyPress

 

    End Sub

 

End Class

现在我们只有这样一处使用这个Event的地方,但是假设我们有100Form,每个Form都有20个这样的TextBox(记住,你做的是通用控件,他可能会被用在任何的地方,会被使用上千次)。那么我们就要这样修改2000次。其中可能只有10个时需要把背景色变成别的颜色,比如耦合色。但是我还是要修改2000个函数的。

当我们终于修改完成之后,客户有发来一封稍有歉意的Mail,说他们还希望能够设定MessageBox的按钮状态和显示属性,大部分是OKCancel按钮和Information形式,个别的是OK按钮和Error形式。看来我们有需要修改我们的TextBox类和那2000个函数了。

而后,用户又来了一个Mail……天哪,看来我们有必要把Mail Service关掉了。因为这样修改对于项目是毁灭性的。我们有必要重新审视一下我们的TextBox类的建立问题了。

我们现在关键的问题就是参数,我们增加一点Event的功能,就需要修改Event的参数列表,然后修改所有使用这个EventHandle函数。但是很多的时候,真正修改函数内部的地方可能很少,甚至没有。我们重复的劳动就是一个个修改Handle函数的参数列表。

那么我们看看.NET是怎么做的,我们看看Form.Closing事件Handle出来的函数。

    Private Sub Form1_Closing(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing

    End Sub

我们把注意力集中到第二个参数,它不是我们前面熟悉的EventArgs,而是CancelEventArgs。而我们看看这个CancelEventArgs里面都有什么。我们看到了e.Cancel.NET把我们此前做的那个Cancel参数通过第二个参数的成员属性传递进来了。这样我们就通过设定e.Cancel来达到我们原先的处理。

这里可能有的人会产生疑问,e参数被声明为ByVal,它应该不能被返回到RaiseEvent调用处的啊?但是事实是可以的。原因是.NET在处理类的实例参数的时候,传进来的不是实例本身,而是实例的指针。而我们ByVak的只不过是保存这个指针地址变量的一个副本。所以即使是ByVal,如果这个参数是类的实例,也可以把成员传递回去。

这样做的好处就是如果还有新的参数加入,我们只需要修改这个CancelEventArgs类和相应的RasiseEvent,调用的HandleEvent如果不需要对应这个新的参数,就没有必要修改了。这个就是面向对象的好处,封装了操作,只通过接口来连接。也就是软件工程里面所说的松耦合。

现在我们已找这个办法修改自己的TextBox类。首先我们要做好这个EventArgs类,模仿CancelEventArgs,我们做一个EnterKeyPressEventArgs

    Public Class EnterKeyPressEventArgs

        Inherits EventArgs

 

        Private m_Cancel As Boolean

        Private m_Message As String

        Private m_BackColor As Color

 

        Public Property Cancel() As Boolean

            Get

                Return m_Cancel

            End Get

            Set(ByVal Value As Boolean)

                m_Cancel = Value

            End Set

        End Property

 

        Public Property Message() As String

            Get

                Return m_Message

            End Get

            Set(ByVal Value As String)

                m_Message = Value

            End Set

        End Property

 

        Public Property BackColor() As Color

            Get

                Return m_BackColor

            End Get

            Set(ByVal Value As Color)

                m_BackColor = Value

            End Set

        End Property

 

        Public Sub New()

            m_Cancel = False

            m_Message = "Empty connect is not validated."

            m_BackColor = Color.Red

        End Sub

 

    End Class

这个类继承自EventArgs,通过私有变量和公共属性来传递参数。为什么不用共有变量呢,有原因的,我心准备在专门写一篇文章说说这个问题。反正这样私有变量加公共属性的办法比公共变量要好。

然后我们修改TextBox类,调用RaiseEvent的地方就可以使用这个类了。

    Public Event EnterKeyPress(ByVal sender As Object, ByVal e As EnterKeyPressEventArgs)

 

    Private Sub MyTextBox_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles MyBase.KeyPress

        'Do something then user press ENTER KEY

        If Asc(e.KeyChar) = 13 Then

            'Create the args instance

            Dim ekpea As New EnterKeyPressEventArgs

            'Send the event with parameters

            RaiseEvent EnterKeyPress(Me, ekpea)

            'Show message box depend on the return parameters

            If ekpea.Cancel = False Then

                Me.BackColor = ekpea.BackColor

                MsgBox(ekpea.Message)

            End If

        End If

    End Sub

我们使用的时候,也可以相应的修改成。

    Private Sub MyTextBox1_EnterKeyPress(ByVal sender As Object, ByVal e As MyTextBox.EnterKeyPressEventArgs) Handles MyTextBox1.EnterKeyPress

        'Some codes ...

        e.Cancel = False

        e.Message = "My message ... "

        e.BackColor = Color.Green

        'Some codes ...

    End Sub

这样即便客户又来信说,我们需要加入一个功能,设定这个MessageBox的按钮类型,默认是VBOKOnlyInformation。我们需要修改的地方首先是这个EventArgs

    Public Class EnterKeyPressEventArgs

        Inherits EventArgs

 

        Private m_Cancel As Boolean

        Private m_Message As String

        Private m_BackColor As Color

        Private m_ButtonStyle As MsgBoxStyle

 

        Public Property Cancel() As Boolean

            Get

                Return m_Cancel

            End Get

            Set(ByVal Value As Boolean)

                m_Cancel = Value

            End Set

        End Property

 

        Public Property Message() As String

            Get

                Return m_Message

            End Get

            Set(ByVal Value As String)

                m_Message = Value

            End Set

        End Property

 

        Public Property BackColor() As Color

            Get

                Return m_BackColor

            End Get

            Set(ByVal Value As Color)

                m_BackColor = Value

            End Set

        End Property

 

        Public Property Style() As MsgBoxStyle

            Get

                Return m_ButtonStyle

            End Get

            Set(ByVal Value As MsgBoxStyle)

                m_ButtonStyle = Value

            End Set

        End Property

 

        Public Sub New()

            m_Cancel = False

            m_Message = "Empty connect is not validated."

            m_BackColor = Color.Red

            m_ButtonStyle = MsgBoxStyle.OKOnly Or MsgBoxStyle.Information

        End Sub

 

    End Class

然后修改RaiseEvent的一句话。

MsgBox(ekpea.Message, ekpea.Style)

而使用的Handle函数只要使用默认值,就不需要修改了。

        - 未完待续 -

posted @ 2005-03-18 10:41  妖居  阅读(1368)  评论(0编辑  收藏  举报