Tuesday, April 15, 2008

CheckBox CheckedChanged Event Recursion

Issue: CheckBox CheckedChanged Event Recursively Called automatically, System.StackOverflowException exception occurs
Level: Intermediate
Knowledge Required: To understand the following solution you must have the knowledge of:

  • CheckBox Control
  • Recursion
  • Add Event Handler (AddHandler)
  • Remove Event Handler (RemoveHandler)

Description:

Sometimes it is observed that whenever we try to change the Checked property of CheckBox within the CheckedChanged Event Control it automatically fires the same event again in such a manner that this firing never stops. For example:


Private Sub CheckBox1_CheckedChanged(ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles CheckBox1.CheckedChanged

    CheckBox1.Checked = Not CheckBox1.Checked

End Sub

In the above example when user clicks on CheckBox1 for the first time then this event will be triggered, so in this event we are toggling the current value i.e. if first time the Checked Property was False then on Click this value is turned to True and then in the same event we are converting its value to False which will again trigger this event and then this event is again converts the value to True and this process goes on until the System.StackOverflowException exception occurs.

The process,

1) FirstTime
Checked = False
2) User Clicked on Check Box
Checked = True (Event triggered)
3) in event Checked = NOT Checked (NOT True = False)
Checked = False (Event triggered)
4) in event Checked = NOT Checked (NOT False = True)
Checked = True (Event triggered)
...
...
...

You may think why we will do this strange thing in the CheckedChanged Event, nobody ever wants to change the Checked property by himself in the CheckedChanged Event, since it is changing by clicking.
But this scenario is a real life example, we can have the situation where we dont want the user to check the checkbox until some other things are NOT full filled OR we can also have another scenario where we want the checkbox to be read only. This can also be accomplished by setting the CheckBox Enable Property to False but this will also Darken our control which we dont want to be happened. What we want is just that when user clicks on checkbox nothing should happen neither its checked is unchecked nor unchecked is checked.

To understand it more accurately, consider a scenario where we have 4 check boxes user can check any 2 of them NOT four of them,



In this scenario we can create a function CanCheckBoxSelect(byref CheckboxToCheck as CheckBox). This function will return True if CheckBox can be checked and False if it cannot (NOTE that I am NOT considering the inside logic of this function because this is NOT our topic) therefore we will add the Coding in CheckedChanged Event as
Private Sub CheckBox_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs)
    Dim chkClicked As CheckBox
    chkClicked = CType(sender, CheckBox) ' Get the Check Box which is Clicked
    ' If this CheckBox cannot be Checked
    If NOT CanCheckBoxSelect(chkClicked) Then
        ' first remove the event handler because we are going to change the Checked Property
        RemoveHandler chkClicked.CheckedChanged, AddressOf CheckBox_CheckedChanged
        ' now change the Checked Property and this will NOT again trigger this Event
chkClicked.Checked = Not chkClicked.Checked
        ' now again add the CheckedChanged event handler
        AddHandler chkClicked.CheckedChanged, AddressOf CheckBox_CheckedChanged
    End If
End Sub
In the above code we can understand the solution that
  1. We have first simply removed this event handler and then
  2. Again added the handler
By removing the Event Handler, this will prevent this event to be triggered again when we are changing the Checked Property manually.

3 comments:

Anonymous said...

TY, from a c# programmer
-you gave me an idea

Dasun Sameera - දසුන් සමීර said...

It's can be solve by using bool variable. not need remove add handlers

Anonymous said...

Yes you can use a bool variable, but this is cleaner and I thank you for providing this. I always hating creating the work-arounds using a myraid of bool variables. Thank you!!