Adding a handler that uses a variable, uses the value of the variable at event time

chacham

New member
Joined
Nov 28, 2023
Messages
4
Programming Experience
10+
Can someone explain the difference to me?

VB.NET:
Public Class Form1
    Private Sub Form1_Load(Sender As Object, Arguments As EventArgs) Handles MyBase.Load
        Dim A As Integer
        Dim B As Button
        For X As Integer = 1 To 3
            A = X
            B = New Button With {.Location = New Point(100 * X, 0)}
            AddHandler B.Click, Sub() B.Text = A
            Controls.Add(B)
        Next

        For X As Integer = 1 To 3
            Dim C As Integer = X
            Dim D As New Button With {.Location = New Point(100 * X, 25)}
            AddHandler D.Click, Sub() D.Text = C
            Controls.Add(D)
        Next

        For Each Control As Control In Controls
            DirectCast(Control, Button).PerformClick()
        Next
    End Sub
End Class

The 1st row of buttons, when clicked, set the 3rd button to "3".
The 2nd row of buttons, when clicked, set their own button to 1, 2, or 3.

1701362917745.png


It seems that adding a handler that uses a variable, uses the variable's value at event time, not at the handler's creation time. Dimming the variable inside the loop creates a new variable each time, and so the variable used in the Handler never changes. I'm curios if there is a way to change this behavior, so that the variable's value at handler creation time is used.
 
The second option creates a closure that does capture the variable when the event handler is created (AddHandler loop).
When invoked the handler then shows what the loop variable was at that time. (1,2,3)
By the way, there is a 5 part article about closures, this last part has links to the previous 4: Closures in VB Part 5: Looping

Are you actually asking for something else, for example to have a variable outside the method that the handler shows the current value of?
 
>Are you actually asking for something else, for example to have a variable outside the method that the handler shows the current value of?

I was just working on a project and noticed the Handler set the wrong value (it was actually setting the right value but to the wrong column in a DataGridView), but when i debugged it, it was being set properly. That's when it clicked that the Handler was being evaluated at runtime, hence it used the last value the variable was set to, instead of the value at the time the Handler was added. So, i created this example to check it out, and realized that i had to create new variables. I posted it here to see if i was missing anything obvious.

In the project, i ended up putting the AddHandler statement in a separate Sub (that's the only statement in the Sub). By calling the Sub from the loop instead of running the AddHandler statement directly, it worked as intended. I understand why, i guess, it's just not obvious.
 
Yes, second option is the right way to handle the closure for lambda.
 
Back
Top