1. Computing & Technology

Discuss in my forum

Dan Mabbutt

Using AddHandler and AddressOf

By , About.com GuideDecember 13, 2006

Follow me on:

Adding Run-Time Event Handlers Dynamically

"Erick" had a problem figuring out how to record the sequence of clicks in a program. The program displayed a matix of CheckBox controls but the key information that was needed was the sequence that they were checked.

Piece of cake, right? Just add an event subroutine that handles the Click event for all of the Checkboxes and capture the sequence.

Private Sub SequenceCapture( _
   ByVal sender As Object, -
   ByVal e As System.EventArgS) _
   Handles CheckBox01.CheckChanged, _
   	Checkbox02.CheckChanged, _

... and so forth followed by ...

   CheckBoxSequence(CheckSeq) = sender.name
   CheckSeq += 1

Not so fast there, sailor. There's more to the problem.

The matrix of CheckBox controls is variable. The number of rows and columns is entered into textboxes and the CheckBox matrix is created in a double loop:

For RowCount = 1 To RowSize
    For ColCount = 1 To ColSize
      Dim ChkBox As New CheckBox
      ChkBox.Name = "Checkbox" & i.ToString + 1
      ChkBox.Location = _
         New Point(20 * ColCount, 20 * RowCount)
      ChkBox.Size = New Size(20, 20)
      Me.Controls.Add(ChkBox)
      i += 1
    Next
Next 

Adding handlers, a "compile-time" solution, doesn't work now. For one thing, you don't even know how many CheckBox controls there will be at run-time. We need a run-time solution instead.

The AddHandler statement fills the bill just fine. Use AddressOf to point to the right subroutine to handle the CheckedChanged event for each CheckBox component.

Dim ChkBox As New CheckBox
AddHandler ChkBox.CheckedChanged, AddressOf SequenceCapture

Here's the source for a complete example program:

Public Class Form1
   Dim CheckBoxSequence() As String
   Dim CheckSeq As Integer = 0
   Private Sub Form1_Load( _
     ByVal sender As System.Object, _
     ByVal e As System.EventArgs) _
     Handles MyBase.Load
     Dim CheckBoxMatrix() As String
     Dim MatrixSize, i, RowCount, ColCount As Integer
     Dim RSize, CSize As Integer
     RSize = CInt(RowSize.Text)
     CSize = CInt(ColSize.Text)
     MatrixSize = RSize * CSize
     ReDim CheckBoxMatrix(MatrixSize - 1)
     ReDim CheckBoxSequence(MatrixSize - 1)
     i = 0
     For RowCount = 1 To RSize
        For ColCount = 1 To CSize
           CheckBoxMatrix(i) = i.ToString
           Dim ChkBox As New CheckBox
           AddHandler ChkBox.CheckedChanged, _
              AddressOf SequenceCapture
           ChkBox.Name = "Checkbox" & i.ToString + 1
           ChkBox.Location = _
              New Point(20 * ColCount, 20 * RowCount)
           ChkBox.Text = ""
           ChkBox.Size = New Size(20, 20)
           Me.Controls.Add(ChkBox)
           i += 1
        Next
     Next
   End Sub

   Private Sub SequenceCapture( _
     ByVal sender As Object, _
     ByVal e As System.EventArgs)
     CheckBoxSequence(CheckSeq) = sender.name
     CheckSeq += 1
   End Sub

   Private Sub Button1_Click( _
     ByVal sender As System.Object, _
     ByVal e As System.EventArgs) _
     Handles Button1.Click
     For i As Int16 = 0 To CheckSeq
        Label1.Text = _
           Label1.Text & CheckBoxSequence(i) & vbCrLf
     Next
   End Sub
End Class
Comments
December 14, 2006 at 11:47 am
(1) Mark :

Excellent. Great use of OO and good event model. I would even go a few steps further. Allow row/column count to vary, create a custom checkbox class with published events the form can subscribe.

I didn’t see anything for handling if someone ‘unchecks’ a box.

For me, the form should do 2 things – get data from the user, show data to the user and provide navigation.

December 14, 2006 at 1:53 pm
(2) Graham :

I copied and pasted the complete code, on the form I placed a Button, a Label and two text boxes one called RowSize and one ColSize, but when I try to run the program I get an error :-
Conversion from String “”to type’Integer’ is not valid.

December 14, 2006 at 6:25 pm
(3) visualbasic :

Mark,

Great comments. The example was designed to illustrate a technical point and is a long way from being a production application.

Graham,

Ummmm … Yeah …. The textboxs have to be initialized with a numeric value since the processing takes place in the Form1.Load event. When I’m trying to be both entertaining and informative, I sometimes leave details like this out.

By the way … how are you coming on checking out the flowchart I sent to you?

December 15, 2006 at 4:04 am
(4) Graham :

Thanks for that, the flow chart is fine the only thing I would add is the ability to search, so that I do not need to go through the complete list to find the site/program I’m after.
I did reply to your email, must be floating around cyberspace somewhere?

December 15, 2006 at 5:15 am
(5) Graham :

Ok, it’s a great example, but not to a novice.
First I needed to initialise the text boxes, after doing so the program ran, now I change the value of the textbox and get an error, so I alter the code and put the part that generates the checkboxes in to it’s own sub which will be called when the form loads and again on ColSize_TextChanged and again on RowSize_TextChanged. Novice ‘There that should work’ Expert ‘No it won’t’
Use step through and find that after dim statements we jump to ColSize_TextChanged then to Private Sub MakeBoxes() Problem ColSize = 4 but RowSize = “” so we get an error.
Below is my code and to me it should work (Rememeber Novice) so why doesn’t it and why does it jump from dim to TextChanged when it hasn’t yet.

Public Class Form1
Dim CheckBoxSequence() As String
Dim CheckSeq As Integer = 0
Dim CheckBoxMatrix() As String
Dim MatrixSize, i, RowCount, ColCount As Integer
Dim RSize, CSize As Integer

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

End Sub

Private Sub SequenceCapture( _
ByVal sender As Object, _
ByVal e As System.EventArgs)
CheckBoxSequence(CheckSeq) = sender.name
CheckSeq += 1
End Sub
Private Sub Button1_Click( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles Button1.Click
For i As Int16 = 0 To CheckSeq
Label1.Text = _
Label1.Text & CheckBoxSequence(i) & vbCrLf
Next
End Sub
Private Sub MakeBoxes()
RSize = CInt(RowSize.Text)
CSize = CInt(ColSize.Text)
MatrixSize = RSize * CSize
ReDim CheckBoxMatrix(MatrixSize – 1)
ReDim CheckBoxSequence(MatrixSize – 1)
i = 0
For RowCount = 1 To RSize
For ColCount = 1 To CSize
CheckBoxMatrix(i) = i.ToString
Dim ChkBox As New CheckBox
AddHandler ChkBox.CheckedChanged, _
AddressOf SequenceCapture
ChkBox.Name = “Checkbox” & i.ToString + 1
ChkBox.Location = _
New Point(20 * ColCount, 20 * RowCount)
ChkBox.Text = “”
ChkBox.Size = New Size(20, 20)
Me.Controls.Add(ChkBox)
i += 1
Next
Next
End Sub

Private Sub ColSize_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ColSize.TextChanged
MakeBoxes()
End Sub

Private Sub RowSize_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles RowSize.TextChanged
MakeBoxes()
End Sub
End Class

December 15, 2006 at 12:34 pm
(6) visualbasic :

“First I needed to initialise the text boxes, after doing so the program ran, now I change the value of the textbox and get an error, so I alter the code …”

Ummmm … There we part company. I tried it again and I don’t get an error when I change the value of the text box. The size of the Checkbox matrix doesn’t change. (It’s created in the Form Load event.) But I don’t get an error. So I don’t know what kind of error you might be seeing here.

Anyway …

I checked out your code and I have to admit that you created a very sneaky bug!! I had to scratch my head twice before I found it.

In fact, this is SUCH a good bug, I’m a little reluctant to just spill the answer. I’m thinking that I might make another blog out of it. I need to go to a meeting and I’ll think about it. In the meantime, you might take another look and see if you can figure it out.

December 15, 2006 at 2:34 pm
(7) Graham :

Sorry, you’re right, there is no error it’s just that the matrix does not change, what tricked me was the line in your article;

The matrix of CheckBox controls is variable. The number of rows and columns is entered into textboxes and the CheckBox matrix is created in a double loop:
I read it as entering a number in the textboxes, changes the Matrix, which is what I’m trying to achieve now. Will look for the very sneaky bug.

December 15, 2006 at 2:43 pm
(8) visualbasic :

I’m writing a new blog (with illustrations) about it right now.

Leave a Comment

Line and paragraph breaks are automatic. Some HTML allowed: <a href="" title="">, <b>, <i>, <strike>
Related Searches addhandler

©2012 About.com. All rights reserved.

A part of The New York Times Company.