Events


A control or other object raises an event to let the program know about some change in circumstances. Sometimes raising an event is also called firing or throwing the event. Specific control classes provide events that are relevant to their special purposes. For example, the Button control provides a Click event to let the program know when the user clicks on the button.

The program responds to an event by creating an event handler that catches the event and takes whatever action is appropriate. Each event defines its own event-handler format and determines the parameters that the event handler will receive. Often, these parameters give additional information about the event.

For example, when part of the form is covered and exposed, the form raises its Paint event. The Paint event handler takes as a parameter an object of type PaintEventArgs. That object’s gr property is a reference to a Graphics object that the program can use to redraw the form’s contents.

Some event handlers take parameters that are used to send information about the event back to the object that raised it. For example, the Form class’s FormClosing event handler has a parameter of type FormClosingEventArgs. That parameter is an object that has a property named Cancel. If the program sets Cancel to True, the Form cancels the FormClosing event and remains open. For example, the event handler can verify that the data entered by the user was properly formatted. If the values didn’t make sense, the program can display an error message and keep the form open.

Although many of a control’s most useful events are specific to the control type, controls do inherit some common events from the Control class. Appendix A summarizes the Control class’s most important events. Controls that inherit from the Control class also inherit these events unless they have overridden the Control class’s behavior.

Creating Event Handlers at Design Time

There are a couple of ways that you can create an event handler at design time. If you open a form in the Form Designer and double-click a control, the code editor opens and displays the control’s default event handler. For example, a TextBox control opens its TextChanged event handler, a Button control opens its Click event handler, and the form itself opens its Load event handler.

To create some other non-default event handler for a control, select the control and then click the Properties window’s Events button (which looks like a lightening bolt). This makes the Properties window list the control’s most commonly used events, as shown in Figure 2-19. If you have defined event handlers already, possibly for other controls, you can select them from the events’ drop-down lists. Double-click an event’s entry to create a new event handler.

image from book
Figure 2-19: Click the Properties window’s Events button to see a list of a control’smost commonly used events.

To create other non-default event handlers or to create event handlers inside the code editor, open the code window, select the control from the left drop-down list, and then select the event handler from the right drop-down list, as shown in Figure 2-20. To create an even handler for the form itself, select “(Form1 Events)” from the left drop-down and then select an event from the right drop-down.

image from book
Figure 2-20: To create an event handler in the code window, select a control from the left drop-down, and then select an event from the right drop-down.

The code window creates an event handler with the correct parameters and return value. For example, the following code shows an empty TextBox control’s Click event handler (note that the first two lines are wrapped in this text but appear on one line in the code editor). Now you just need to fill in the code that you want to execute when the event occurs.

  Private Sub TextBox1_Click(ByVal sender As Object, ByVal e As System.EventArgs) _  Handles TextBox1.Click End Sub 

WithEvents Event Handlers

If you declare an object variable using the WithEvents keyword, you can catch its events. After you declare the variable, you can select it in the code designer’s left drop-down, just as you can select any other control. Then you can select one of the object’s events from the right drop-down.

When the code assigns an instance of an object to the variable, any event handlers defined for the variable receive the object’s events.

Usually, you don’t need to create WithEvents variables for controls because Visual Basic does it for you. However, using a variable declared WithEvents lets you enable and disable events quickly and easily. For example, suppose that a program wants to track a PictureBox’s mouse events at some times, but not at others. It could declare a PictureBox variable as shown in the following code.

  Private WithEvents m_Canvas As PictureBox 

When the program wants to receive events, it can set this variable equal to its PictureBox control as in this code. Now the variable’s event handlers such as m_Canvas_MouseDown, m_Canvas_MouseMove, and m_Canvas_MouseUp are enabled.

  m_Canvas = PictureBox1 

When it no longer wants to receive these events, the program can set m_Canvas to Nothing as in the following statement. While m_Canvas is Nothing, it has no associated control to generate events for it.

  m_Canvas = Nothing 

Setting Event Handlers at Runtime

Not only can you create event handlers at design time, but you can also assign them at runtime. First create the event handler. You must get the routine’s parameters exactly correct for the type of event handler you want to create. For example, a TextBox control’s Click event handler must take two parameters with types System.Object and System.EventArgs.

To ensure that you get the details right, you can start by creating an event handler for a normal control at design time. Select the control from the code designer’s left drop-down, and then select the event from the right. Change the resulting event handler’s name to something appropriate (for example, you might change Button1_Click to ToolClicked) and remove the Handles statement that ties the event handler to the control. You can also delete the original control if you don’t need it for anything else.

Now you can use the AddHandler and RemoveHandler statements to add and remove the event handler from a control. The following code shows how a program can switch the event handler that a button executes when it is clicked.

When RadioButton1 is selected or cleared, its CheckedChanged event handler adds or removes the ButtonHandler1 event handler from the Button1 control’s Click event. Similarly, when RadioButton2 is selected or cleared, its CheckedChanged event handler adds or removes the ButtonHandler2 event handler from the Button1 control’s Click event.

The ButtonHandler1 and ButtonHandler2 event handlers simply display a message telling you which is executing. The form’s Load event handler selects the first radio button.

  ' Add or remove ButtonHandler1. Private Sub RadioButton1_CheckedChanged(ByVal sender As System.Object, _  ByVal e As System.EventArgs)Handles RadioButton1.CheckedChanged     If RadioButton1.Checked Then         AddHandler Button1.Click, AddressOf ButtonHandler1     Else         RemoveHandler Button1.Click, AddressOf ButtonHandler1     End If End Sub ' Add or remove ButtonHandler2. Private Sub RadioButton2_CheckedChanged(ByVal sender As System.Object, _  ByVal e As System.EventArgs) Handles RadioButton2.CheckedChanged     If RadioButton2.Checked Then         AddHandler Button1.Click, AddressOf ButtonHandler2     Else         RemoveHandler Button1.Click, AddressOf ButtonHandler2     End If End Sub ' Display a message telling which event handler this is. Private Sub ButtonHandler1(ByVal sender As System.Object, _  ByVal e As System.EventArgs)     MessageBox.Show("ButtonHandler1") End Sub Private Sub ButtonHandler2(ByVal sender As System.Object, _  ByVal e As System.EventArgs)     MessageBox.Show("ButtonHandler2") End Sub ' Start with RadioButton1 selected. Private Sub Form1_Load(ByVal sender As System.Object, _  ByVal e As System.EventArgs) Handles MyBase.Load     RadioButton1.Checked = True End Sub  

You can also use AddHandler and RemoveHandler to enable and disable events as needed much as the previous section showed how to enable and disable events using variables declared with the WithEvents keyword.

AddHandler and RemoveHandler allow you to switch one or two events relatively easily. If you must switch many event handlers for the same control at once, however, it may be easier to use a variable declared using the WithEvents keyword.

Changing Design Time Event Handlers

An event handler you create for a particular control at design time is just like any other event handler subroutine at runtime. You can use RemoveHandler to detach it from the control’s events, and you can use AddHandler to reattach it to an event.

Typically, an event handler that you create attached to a particular control seems different from those you write separately from any control. It may follow different naming conventions (perhaps btnTool_Click versus ToolClickEventHandler), and its declaration includes a Handles clause that a hand-coded event-handling routine will not have.

This lack of symmetry may make switching these event handlers with those you create on your own a bit confusing. On the other hand, using AddHandler and RemoveHandler to remove and reattach an event handler is relatively straightforward. As long as you don’t mix and match the two kinds of event handlers, this should cause no confusion.

Control Array Events

Visual Basic 6 and earlier versions allowed you to use control arrays. A control array was an array of controls with the same name that shared the same event handlers. A parameter to the event handlers gave the index of the control in the array that fired the event. If the controls perform closely related tasks, the common event handler may be able to share a lot of code for all of the controls. Visual Basic .NET does not allow control arrays, but you can get similar effects in a couple of ways.

First, suppose that you add a control to a form and give it event handlers. Then you copy and paste the control to make other controls on the form. All these controls share the event handlers you already created by default. If you look at the event handlers’ code, you’ll see the Handles statements list all of the copied controls. You can also modify an event handler’s Handles clause manually to attach it to more than one control.

Another way to make controls share event handlers is to attach them to the controls by using the AddHandler statement.

An event handler’s first parameter is a variable of the type System.Object that contains a reference to the object that raised the event. The program can use this object and its properties (for example, its Name property) to determine which control raised the event and take appropriate action.

Validation Events

Data validation is an important part of many applications. Visual Basic provides two events to make validating data easier: Validating and Validated.

The Validating event fires when the code should validate a control’s data. This happens when the control has the input focus and the form tries to close, and when focus moves from the control to another control that has its CausesValidation property set to True.

The Validation event handler can verify that the data in a control has a legal value and take appropriate action if it doesn’t. For example, consider the form shown in Figure 2-21. The first TextBox control’s Validating event handler checks that the control’s value contains exactly five digits. If the value does not contain five digits, as is the case in the figure, the program uses an ErrorProvider control to flag the TextBox’s value as being in error and moves the input focus back to the TextBox. The ErrorProvider displays the little exclamation mark icon to the right of the control and makes the icon blink several times to get the user’s attention. When the user hovers the mouse over the icon, the ErrorProvider displays the error text in a tooltip.

image from book
Figure 2-21: The Validating event fires when the focus moves to a control that has CausesValidation set to True.

The second TextBox control in this example has a CausesValidation property value of False. When the user moves from the first TextBox control to the second one, the Validating event does not fire and the TextBox control is not flagged. The third TextBox control has CausesValidation set to True so, when the user moves into that TextBox control, the first TextBox’s Validating event fires, and the value is flagged if it is invalid. The Validating event also fires if the user tries to close the form.

The following code shows the Validating event handler used by this example. Notice that the Handles clause lists all three TextBoxes’ Validating events so this event handler catches the Validating event for all three controls.

The event handler receives the control that raised the event in its sender parameter. It uses DirectCast to convert that generic Object into a TextBox object and passes it to the ValidateFiveDigits subroutine. It also passes the e.Cancel parameter, so the subroutine can cancel the action that caused the event if necessary.

ValidateFiveDigits checks the TextBox control’s contents and sets its cancel_event parameter to True if the text has nonzero length and is not exactly five digits. This parameter is passed by reference, so this changes the original value of e.Cancel in the calling event handler. That will restore focus to the TextBox that raised the event and that contains the invalid data.

If cancel_event is True, the value is invalid, so the program uses the ErrorProvider component named ErrorProvider1 to assign an error message to the TextBox control.

If cancel_event is False, then the value is valid so the program blanks the ErrorProvider component’s message for the TextBox.

  'Validate the TextBox's contents. Private Sub TextBox1_Validating(ByVal sender As Object, _  ByVal e As System.ComponentModel.CancelEventArgs) _  Handles TextBox1.Validating, TextBox2.Validating, TextBox3.Validating     ' Get the TextBox..     Dim text_box As TextBox = DirectCast(sender, TextBox)     ' Validate the control's value.     ValidateFiveDigits(text_box, e.Cancel) End Sub ' Verify that the TextBox contains five digits. Private Sub ValidateFiveDigits(ByVal text_box As TextBox, _  ByRef cancel_event As Boolean)     If text_box.Text.Length = 0 Then         ' Allow a zero-length string.         cancel_event = False     Else         ' Allow five digits.         cancel_event = Not (text_box.Text Like "##")     End If     ' See if we're going to cancel the event.     If cancel_event Then         ' Invalid. Set an error.         ErrorProvider1.SetError(text_box, _             text_box.Name & " must contain exactly five digits")     Else        ' Valid..Clear any error.        ErrorProvider1.SetError(text_box, "")     End If End Sub 

Separated Validation

A control’s Validated event fires after the focus successfully leaves the control, either to another control with CausesValidation set to True or when the form closes. The control should have already validated its contents in its Validating event, hence the event name Validated.

This event doesn’t really have anything directly to do with validation, however, and it fires whether or not the code has a Validating event handler and even if the control’s value is invalid. The only time it will not execute is if the validation does not complete. That happens if the Validating event handler cancels the event causing the validation.

The previous section showed how to set or clear a control’s error in its Validating event handler. An alternative strategy is to set errors in the Validating event handler and clear them in the Validated event handler, as shown in the following code. If the control’s value is invalid, the Validating event handler cancels the event causing the validation so the Validated event does not occur. If the control’s value is valid, the Validating event handler does not cancel the event and the Validated event handler executes, clearing any previous error.

  ' Validate the TextBox's contents. Private Sub TextBox1_Validating(ByVal sender As Object, _  ByVal e As System.ComponentModel.CancelEventArgs) _  Handles TextBox1.Validating, TextBox2.Validating, TextBox3.Validating     ' Validate the control's value.     ValidateFiveDigits(DirectCast(sender, TextBox), e.Cancel) End Sub ' Verify that the TextBox contains five digits. Private Sub ValidateFiveDigits(ByVal text_box As TextBox, _  ByRef cancel_event As Boolean)     ' Cancel if nonzero length and not five digits.     cancel_event = (text_box.Text.Length <> 0) And _         Not (text_box.Text Like "##")     ' See if we're going to cancel the event.     If cancel_event Then         ' Invalid. Set an error.         ErrorProvider1.SetError(text_box, _             text_box.Name & " must contain exactly five digits")     End If End Sub ' Validation succeeded. Clear any error. Private Sub TextBox1_Validated(ByVal sender As Object, _  ByVal e As System.EventArgs)_  Handles TextBox1.Validated, TextBox2.Validated, TextBox3.Validated     ' Valid. Clear any error.     ErrorProvider1.SetError(DirectCast(sender, TextBox), "") End Sub 

Deferred Validation

By keeping focus in the control that contains the error, the previous approaches force the user to fix problems as soon as possible. In some applications, it may be better to let the user continue filling out other fields and fix the problems later. For example, a user who is touch-typing data into several fields may not look up to see the error until much later, after failing to enter many values in the invalid field and wasting a lot of time.

The following code shows one way to let the user continue entering values in other fields. The Validating event handler calls the ValidateFiveDigits subroutine much as before, but this time ValidateFiveDigits does not take the cancel_event parameter. If the TextBox object’s value has an error, the routine uses the ErrorProvider to assign an error message to it and exits.

When the user tries to close the form, the FormClosing event handler executes. This routine assumes that some field contains invalid data, so it sets e.Cancel to True. It then calls the function IsInvalidField for each of the controls that it wants to validate. If IsInvalidField returns True, the event handler exits, e.Cancel remains True, and the form refuses to close. If all of the fields pass validation, then the event handler sets e.Cancel to False, and the form closes.

Function IsInvalidField uses the ErrorProvider’s GetError method to get a control’s assigned error message. If the message is blank, the function returns False to indicate that the control’s data is valid. If the message is not blank, then the function displays it in a message box, sets focus to the control, and returns True to indicate that the data is invalid.

  ' Validate the TextBox's contents. Private Sub TextBox1_Validating(ByVal sender As Object, _  ByVal e As System.ComponentModel.CancelEventArgs) _  Handles TextBox1.Validating, TextBox2.Validating, TextBox3.Validating     ' Validate the control's value.     ValidateFiveDigits(DirectCast(sender, TextBox)) End Sub ' Verify that the TextBox contains five digits. Private Sub ValidateFiveDigits(ByVal text_box As TextBox)     ' See if the data is valid.     If (text_box.Text.Length <> 0) And _         Not (text_box.Text Like "##") _     Then         ' Invalid. Set an error.         ErrorProvider1.SetError(text_box, _             text_box.Name & " must contain exactly five digits")     Else         ' Valid. Clear the error.         ErrorProvider1.SetError(text_box, "")     End If End Sub ' See if any fields have error messages. Private Sub Form1_FormClosing(ByVal sender As Object, _  ByVal e As System.Windows.Forms.FormClosingEventArgs) _  Handles Me.FormClosing     ' Assume we will cancel the close.     e.Cancel = True     ' Check for errors.     If IsInvalidField(TextBox1) Then Exit Sub     If IsInvalidField(TextBox3) Then Exit Sub     ' If we got this far, the data's okay.     e.Cancel = False End Sub ' If this control has an error message assigned to it, ' display the message, set focus to the control, ' and return True. Private Function IsInvalidField(ByVal ctl As Control) As Boolean     ' See if the control has an associated error message.     If ErrorProvider1.GetError(ctl).Length = 0 Then         ' No error message.         Return False     Else         ' There is an error message.         ' Display the message.         MessageBox.Show(ErrorProvider1.GetError(ctl))         ' Set focus to the control.         ctl.Focus()         Return True     End If End Function 

If the focus is in a TextBox when the form tries to close, its Validating event fires before the form’s FormClosing event so the TextBox control has a chance to validate its contents before the FormClosing event fires.




Visual Basic 2005 with  .NET 3.0 Programmer's Reference
Visual Basic 2005 with .NET 3.0 Programmer's Reference
ISBN: 470137053
EAN: N/A
Year: 2007
Pages: 417

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net