开发者

How can I process a form's events in another class / module automatically in VB.NET?

Here's my code:

Public Class Form1

End Class

Public Class Form1Handler
    Inherits Form1
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        MsgBox("I")
    End Sub
End Class

I'm trying to get Form1Handler to process Form1's events automatically. How can I do this? Should I use a module instead? I'm doing this in Visual Basic 2010.

I don't want to have to make an event handler in Form1 and then pipe it to the other class / modu开发者_Go百科le. Is there some way to automatically "pipe" the events from form1 to form1handler?


If you need to handle a button or other control events outside the form class, you can make a user control to inherit the control, and then handle the events in the user control class. For example, this user control consists of an internal button control named mbutton:

Public Class mb
  Private Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles mButton.Click
  MsgBox("click")
  End Sub
End Class

You can use it in the main form like this:

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
  b = New mb
  Me.Controls.Add(b)
  b.Name = "testbutton"
  b.Left = 40 : b.Top = 40 : b.Width = 90 : b.Height = 50
End Sub

The click event is handled inside the mb class.


I realize that this thread is old, but I stumbled upon it in search of the answer to the same question. Hopefully this may help someone else. xpda's answer was good and does work, however it doesn't work with buttons created with the Form Designer, my solution does and is an alternative to xpda's method.

For this example I have Form1 with 2 buttons (Buttton1 and Button2) and a textbox (textbox1). I have also created a module (Module1). I have kept it simple and it should be easy to understand.

Module Module1
Public WithEvents ButtonClick1 As Button = Form1.Button1
Public WithEvents ButtonClick2 As Button = Form1.Button2

Public Sub MyButtons(sender As System.Object, e As System.EventArgs) Handles _
ButtonClick1.Click, 
ButtonClick2.Click

    If sender Is ButtonClick1 Then Form1.TextBox1.Text = "Button1 clicked"
    If sender Is ButtonClick2 Then Form1.TextBox1.Text = "Button2 clicked"
End Sub
End Module

At the top of the Module you can have as many WithEvents that you need, one for each control. Keep in mind that every WithEvents you create should be followed by (in this example) with the event after the Handles clause in the MyButtons sub.

You must call the sub during the Form Load event or your program will not see the Module code. This is important to understand. If you have more than one sub, you must call them all.

Calling the Module from Form1 is as follows:

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

Module1.MyButtons(Nothing,Nothing)

End Sub

Once this is done, All click events from Button1 and Button2 will be handled in the Module. You can include other events for the Buttons in the Module or in the Form.

BTW, I should also add that you don't have to create a single sub to handle all events. In this example you could have created 2 subs, one for each button. Also, the name of the sub will never be called so it doesn't matter what you call it. The Button Click events will automatically be handled by the Module as if you wrote it in the Form code.

One more thing...

Another option is to create a Module with a subroutine that you want to handle the Button.Click and then from the Form menu use the AddHandler clause.

Module Module1

Public Sub MySub()

Form1.TextBox1.Text = "Button Clicked"

End Sub
End Module

The Form Code would look like this...

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

    AddHandler Button1.Click, AddressOf Module1.MySub

End Sub

Using this method requires a different Sub for every button.click event since you want each button to do different things.

Well, that's 3 ways of doing the same thing, each with it's own strengths and weaknesses.


I always think that a good answer is the answer that tells how, exactly, we could handle Form1.Button1.Click (or whatever) in Form1Handler.

You could make your controls in Form1 as Protected, at least, instead of Private.

How?

In Form1.Designer.vb: At the end of the code, you should have:

Public Partial Class Form1
    ' ...
    Private Button2 As System.Windows.Forms.Button
    Private Button1 As System.Windows.Forms.Button
End Class

^^ Then change Private to Protected...

    Protected WithEvents Button2 As System.Windows.Forms.Button
    Protected WithEvents Button1 As System.Windows.Forms.Button

Then add WithEvents to ensure your buttons are declared with events.

Or in your IDE designer (Visual Studio 2010 or SharpDevelop) select your button, and in the properties tab, sets its Modifiers property (list) to "Protected". That will change its declaration in Form1.Designer.vb. I know that won't add "WithEvents".

Now, you can create Form1Handler that inherits from Form1.

How do I add an event handler in your Form1Handler?

First create a method that should handle your Button click, in your Form1Handler Class.

Private Sub HandleButtonClick(sender As Object, e As EventArgs)
    ' Instructions for Clicks goes here...
End Sub

Then create a method that ties Button clicks to the method above

Private Sub AddHandlersToButtonClick()
    AddHandler Button1.Click, AddressOf HandleButtonClick
    AddHandler Button2.Click, AddressOf HandleButtonClick
    ' Add as many handlers as you wish, calling as many methods as you wish...
End Sub

Last, in your Form1Handler Class, add a call to the previous method upon loading:

Private Sub OnForm1Handler_Load() Handles Me.Load
     AddHandlersToButtonClick()
End Sub

Now, when you load your Form1Handler that inherits from Form1, HandleButtonClick(..) is launched each time you click on Button1 or Button2. Now, you may want to do something different when you click on Button3 and when your mouse enters Panel1... It's the same:

    ' Creates as many methods you wish for each of your Form1 Controls,
    ' ensuring those controls are declared as Protected in Form1.
    Private Sub HandleButton1Click(sender As Object, e As EventArgs)
        ' ...
    Private Sub HandleButton2Click(sender As Object, e As EventArgs)
    Private Sub HandleButton3Click(sender As Object, e As EventArgs)
    Private Sub HandlePanel1MouseEnter(sender As Object, e As EventArgs)

    ' Then writes in AddHandlersToButtonClick() the dynamic Events handlers
        AddHandler Button1.Click, AddressOf HandleButton1Click
        AddHandler Button2.Click, AddressOf HandleButton2Click
        AddHandler Button3.Click, AddressOf HandleButton3Click
        AddHandler Panel1.MouseEnter, AddressOf HandlePanel1MouseEnter

Then what if you have 300 buttons to handle?

Okay! If, like me, you are a lazy man, and you just want to do litte things for some buttons, and call bigger methods for others, you could use the Tag Property of your Button in the IDE:

  • For Button1 -> Tag = 1
  • For Button2 -> Tag = 2
  • ...
  • For Button300 -> Tag = 300

Then, just use the method provided above, and add a Tag Property check, with something like:

Private Sub HandleButtonClick(sender As Object, e As EventArgs)
    Dim MyButton As System.Windows.Forms.Button
    Dim MyButtonIndex As Integer

    If TypeOf(MyButton) Is System.Windows.Forms.Button Then ' You should check it's a Button.
        MyButton = CType(sender, System.Windows.Forms.Button) ' Option Strict On - Always !
        If Integer.TryParse(MyButton.Tag.ToString(), MyButtonIndex) Then
            Select Case MyButtonIndex
                Case 1:
                    ' Little instruction
                Case 2:
                    ' Call a bigger method, with newer parameters
                    Call HandleMainFormButton1(MyButton, "Houston we have a problem !")

                ' ...
                Case 300:
                    Call HandleMainFormButton300("Just kidding..!")
                Case Else
                    ' This is NOT an indexed Button.
                    MessageBox.Show("You've forgotten to handle button " + MyButtonIndex.ToString())
            End Select
        End If
    End If
End Sub

^^ CRAZY! 300+ checks to do for Button number 300... Don't forget to add handlers for your 300 buttons...

AddHandler Button1.Click, AddressOf HandleButtonClick
AddHandler Button2.Click, AddressOf HandleButtonClick
AddHandler Button3.Click, AddressOf HandleButtonClick
' ...
AddHandler Button299.Click, AddressOf HandleButtonClick
AddHandler Button300.Click, AddressOf HandleButtonClick


I'll give more trial to the idea:

What about Button1.Click already handled in Form1?

Well, look at this piece of code:

Public Partial Class Form1
    Private Sub Button1Click(sender As Object, e As EventArgs) Handles Button1.Click
        MessageBox.Show("Form1 : " + Button1.Text)
    End Sub

    Public Sub New()
        Me.InitializeComponent()
    End Sub
End Class

Public Class Form1Handler
    Inherits Form1

    Private Sub HandleForm1HandlerButton1Click(sender As Object, e As EventArgs)
        MessageBox.Show("Form1Handler : " + Button1.Text)
    End Sub

    Private Sub AddHandlersToButtonClick()
        AddHandler Button1.Click, AddressOf HandleForm1HandlerButton1Click
    End Sub

    Private Sub OnMainFormHandlerLoad() Handles Me.Load
        AddHandlersToButtonClick()
    End Sub
End Class

When you click on Button1 in Form1, you have one dialog box:

MainForm: This is Button1 [OK]

But when you click on Button1 in Form1Handler, you have TWO dialogs:

First: Form1: This is Button1 [OK]

Then: Form1Handler: This is Button1 [OK]

Workaround if you want to get rid of Handlers in Form1:

Workaround 1:

Changes in Form1 Private Sub Button1Click(...) to Public.

    Public Sub Button1Click(sender As Object, e As EventArgs) Handles Button1.Click

Then add an Handler removal in Form1Handler:

    Private Sub AddHandlersToButtonClick()
        RemoveHandler Button1.Click, AddressOf Button1Click
        AddHandler Button1.Click, AddressOf HandleForm1HandlerButton1Click
    End Sub

This will do the trick, by removing the call to Button1Click(...) in Form1 from a method of Form1Handler.

Workaround 2: (and that's my choice)

If only you have to set a click handler for Button1 in Form1, change its Private state to Protected Overridable.

Public Partial Class Form1
    Protected Overridable Sub Button1Click(sender As Object, e As EventArgs) Handles Button1.Click
        MessageBox.Show("Form1 : " + Button1.Text)
    End Sub
    ' ...
End Class

And this is your Form1Handler class:

Public Class Form1Handler
    Inherits Form1

    Protected Overrides Sub Button1Click(sender As Object, e As EventArgs)
        MessageBox.Show("Form1Handler : " + Button1.Text)
    End Sub
End Class

There is no need to use AddHandlersToButtonClick().

There is no need to use HandleForm1HandlerButton1Click().

With the keyword Overrides, you just redefine each Button1Click, Button2Click, ..., Button300Click methods; assuming your goal is to create a bunch of whole new instructions in Form1Handler...

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜