Event Handling

Create, implement, and handle events.

When you perform an action with an object, the object in turn raises events in the application. Dragging the title bar of a form and moving it around, for example, generates an event; resizing a form generates another event. A large portion of code for any typical Windows application is the code that is responsible for handling various events that the application responds to. Events are at the heart of graphical user interface (GUI)–based programming. An event handler is a method that is executed as a response to an event.

Not all events are triggered by user actions. Events may be triggered by changes in the environment such as the arrival of an email message, modifications to a file, changes in the time and completion of program execution, and so on.

With C#, you can define your own custom events that a class will listen to (you'll see how to do this in Chapter 4). You can also handle an event by executing custom code when the event is fired. The following sections discuss two different ways to handle events:

  • Handling events by attaching a delegate

  • Handling events by overriding a protected method of a base class

Handling Events by Attaching a Delegate

When you create a Windows form, it inherits from the Form class. The Form class has a set of events that are already defined and that you can access through the Properties window (see Figure 1.16). If your program needs to take actions when one of those events is fired, it must define an appropriate event handler. The event handler must be registered with the event source so that when the event occurs, the handler will be invoked (this is also referred to as event-wiring). It is possible to have multiple event handlers interested in responding to an event. It is also possible to have a single event handler respond to multiple events.

Figure 1.16. The Properties window lets you access events that are defined for an object.


The visual designer uses event wiring through delegates for handling events, so for most of the book it is also the preferred approach to event handling.

STEP BY STEP

1.9 Handling the MouseDown Event

1.
Open the project 316C01. In the Solution Explorer right-click the project name and select Add, Add Windows Form from the context menu. Name the new form StepByStep1_9 and click the Open button.

2.
Open the Properties window of the form. Change the Text property to Event Handling Form.

3.
In the Properties window, click the Events icon (which looks like a lightning bolt; refer to Figure 1.16) on the toolbar.

4.
Look for an event named MouseDown(), and double-click the row containing the MouseDown event. This takes you to the code view, where Visual Studio .NET inserts a template for the MouseDown event handler. Add code to the event handler so that it looks like this:

private void StepByStep1_9_MouseDown(
 object sender, System.Windows.Forms.MouseEventArgs e)
{
    MessageBox.Show(
     String.Format("X ={0}, Y={1}", e.X, e.Y),
     String.Format("The {0} mouse button hit me at:",
      e.Button.ToString()));
}

5.
Insert the following Main() method after the event handling code you just added:

 [STAThread]
static void Main()
{
    Application.Run(new StepByStep1_9());
}

6.
Set the form as the startup object. Run the project. Observe that whenever you click the form area, a message box appears, displaying the position of the click and whether the left or right mouse button is pressed (see Figure 1.17).

Figure 1.17. The event handler displays a message box showing event-related data.



Step by Step 1.9 involves responding to the MouseDown event of a form. The form inherits the MouseDown event (and many others) from its base class Form. The Properties window lets you see all the events that are available for a control or another object. You choose MouseDown from that list, and when you double-click the event name, the designer switches to the code view and inserts a template for the MouseDown event handler. You insert a line of code that generates a message box, showing the coordinates of the point at which the mouse button is pressed. This information comes from the MouseEventArgs parameter, passed to the event handling method.

The name of the event handler is StepByStep1_9_MouseDown (that is, it uses the form ClassName_EventName). Visual Studio .NET follows this general naming convention for naming event handlers. An event handler normally has a void return type and accepts two arguments: the object on which the event occurred and an argument of type EventArgs (or a type derived from it, such as MouseEventArgs) that contains event-related data. In the StepByStep1_9_MouseDown event handler, the second argument is of type MouseEventArgs, and it contains data that is specific to mouse events (such as the position where the button was pressed).

Table 1.7 shows the kind of information that can be retrieved from the MouseEventArgs object. The type of the second argument depends on the nature of event. Visual Studio .NET automatically determines it for you, but if you write the event handler manually, you have to look in the documentation to find its correct type. The code inside the event handler is straightforward; it displays a message box that shows coordinates of the mouse location as well as which mouse button is pressed.

Table 1.7. MouseEventArgs Properties
MemberDescription
ButtonReturns a value of type MouseButtons that specifies which mouse button is pressed
ClicksReturns the number of times the mouse button is pressed and released
DeltaActs as a signed count of the number of detents (that is, notches of the mouse wheel) the mouse wheel has rotated
XSpecifies the x-coordinate of a mouse click
YSpecifies the y-coordinate of a mouse click

How does the event handler get wired up with the actual event? The designer does it for you, when you double-click the event name in the Properties window. You can expand the designer-generated code to find the following line of code:

this.MouseDown +=
   new System.Windows.Forms.MouseEventHandler(
     this.StepByStep1_9_MouseDown);

This looks like a complex statement. If you break it down to understand it properly, however, you'll see that there are three parts to it:

  • MouseDown is the name of an event.

  • MouseEventHandler is the delegate of the MouseDown event.

  • StepByStep1_9_MouseDown is the name of an event handler.

And here is the role each of them is playing:

  • The MouseDown event is raised when a mouse button is pressed. A set of event handlers can be attached to this event.

    When the event is fired, it invokes all the attached event handlers. An event handler can be attached to this event only through its delegate object.

  • The delegate type of the MouseDown event is MouseEventHandler. You can add event handlers to a MouseDown event only by adding new instances of the delegate to it. A delegate is a special type that is capable of storing a reference to a method with a specific signature (that is, the arguments and return type). Because it stores references of methods, a delegate can also invoke the methods dynamically when the event occurs. In the Visual Studio .NET documentation, the definition of MouseEventHandler delegate looks like this:

    public delegate void MouseEventHandler(
    object sender, MouseEventArgs e);
    

    This means that MouseEventHandler is capable of storing references to any method whose return type is void and that accepts two arguments: the first one of type System.Object and the other one of type MouseEventArgs. The StepByStep1_9_MouseDown event handler signature matches the criteria of this delegate, and hence its reference can be stored in an instance of a delegate of type MouseEventHandler.

    NOTE

    Detaching an Event Handler You can detach an event handler from an event by using the -= syntax that is similar to the += syntax. Although detaching an event handler is generally not required, you might want to detach an event if at runtime, you are no longer interested in responding to a particular event.


    When you have an instance of the MouseEventHandler delegate, you can attach it to the event by using the addition syntax. += is used in the example, so if any event handlers are already attached to this event by the base class, they remain in the list.

  • StepByStep1_9_MouseDown is the name of the method that is responding to this event. The keyword qualifies it for the current instance of the form. When a method name is used alone, without any argument list, it works as a reference to the actual method definition. That reference is passed to the delegate. At a later stage, when the event occurs, that method is invoked through its reference that is maintained by the delegate object.

EXAM TIP

Adding Versus Replacing Delegates When you are attaching delegates, you should usually use the += syntax rather than the = syntax. This is because = attaches the current delegate, and any other previously attached delegates are lost. Using += ensures that you preserve the list of previously attached event handlers.


To manually write code to handle an event, you would follow these steps:

1.
Look up the Visual Studio .NET documentation to find the appropriate event for a class.

2.
Find out the delegate type for this event.

3.
Based on the delegate signature, create an event handler.

4.
Create an instance of the event's delegate that contains a reference to the event handler method.

5.
Add to the event the delegate instance from step 4.

From these steps, you can see that the designer takes a lot of details away from you, and what you are required to do is simply write the actual code that will be executed when the event occurs.

As mentioned earlier in this chapter, it is possible to attach multiple event handlers to an event. Step by Step 1.10 shows how to attach a second event handler to the MouseDown event from Step by Step 1.9. When you execute the code and press the mouse button on the form, both event handlers are executed.

STEP BY STEP

1.10 Attaching Multiple Event Handlers to the MouseDown Event

1.
Open the project 316C01. In the Solution Explorer right-click the project name and select Add, Add Windows Form from the context menu. Name the new form StepByStep1_10 and click on the Open button.

2.
Open the Properties window for the form. Change the form's Text property to Multiple Events Handling Form.

3.
Search for the MouseDown event, and double-click on the row that contains the MouseDown event. Modify its event handler to look like this:

private void StepByStep1_10_MouseDown(object sender,
    System.Windows.Forms.MouseEventArgs e)
{
    MessageBox.Show(
      String.Format("X ={0}, Y={1}", e.X, e.Y),
      String.Format("The {0} mouse button hit me at:",
        e.Button.ToString()));
}

4.
Switch to the design view, and look again for the MouseDown event in Properties window. If you again double-click the row that contains the MouseDown event, you see that a new event handler is not inserted. Therefore, you need to switch to the code view and add the following code for a second event handler:

private void SecondEventHandler(
  object sender, MouseEventArgs e)
{
    Form frm1_10 = (Form) sender;
    if (frm1_10.BackColor== Color.AntiqueWhite)
        frm1_10.BackColor = Color.LightCoral;
    else
        frm1_10.BackColor = Color.AntiqueWhite;
}

5.
Insert the following Main() method after the event handling code from step 4:

[STAThread]
static void Main()
{
    StepByStep1_10 frm1_10= new StepByStep1_10();
    frm1_10.MouseDown += new MouseEventHandler(
      frm1_10.SecondEventHandler);
    Application.Run(frm1_10);
}

6.
Set the form as the startup object. Run the project. Try clicking on the form with the left and right mouse buttons, and the form changes background color in addition to responding with a message box on every click.


In Step by Step 1.10 you add an event handler to the newly created instance of the form StepByStep1_10. The form then has two event handlers registered with the MouseDown event. The first event handler, inserted through the Properties window, is attached to the event when the InitializeComponent event is fired as part of the creation of a new instance of StepByStep1_10. The order in which both event handlers are executed is the order in which they were attached to the event.

Handling Events by Overriding a Protected Method of a Base Class

When you create a Windows form, it inherits from the Form class. By virtue of this inheritance, it has a set of public and protected methods and properties available to it from one of its base classes. The class view lets you see all the inherited members (see Figure 1.18). Some of the classes provide sets of protected methods that raise events. You can easily identify these classes because their naming convention is the word On followed by the name of the event. For example, OnMouseDown() is the protected method of the Form class that raises the MouseDown event. The Form class gets this protected method from the Control class.

Figure 1.18. The class view lets you explore the complete inheritance hierarchy.


The section “Handling Events by Attaching a Delegate” describes how to wire events through the use of delegate objects. An alternative way is to override the On method and write the event handling code there. Step by Step 1.11 demonstrates how to do that.

STEP BY STEP

1.11 Handling Events by Overriding the OnMouseDown Event

1.
Open the project 316C01. In the Solution Explorer right-click the project name and select Add, Add Windows Form from the context menu. Name the new form StepByStep1_11 and click the Open button.

2.
Open the Properties window of the form. Change the Text property of the form to Event Handling through OnMouseDown.

3.
Open the class view by selecting View, Class View (or by pressing Ctrl+Shift+C). Navigate to the StepByStep1_11 node. Expand the Bases and Interfaces node. You should see a node corresponding to the base class Form. Keep expanding until you see members of the Control class (see Figure 1.18).

4.
In the expanded tree, look for a method in the Control class named OnMouseDown(). Right-click the method name and select Add, Override from the context menu. This generates a template for the OnMouseDown() method in your program and switches to code view. Modify the OnMouseDown() method so that it looks like this:

protected override void OnMouseDown(
     System.Windows.Forms.MouseEventArgs e)
{
    MessageBox.Show(
      String.Format("X ={0}, Y={1}", e.X, e.Y),
      String.Format("The {0} mouse button hit me at:",
        e.Button.ToString()));
}

5.
Enter the following code for the Main() method after the OnMouseDown() method:

[STAThread]
static void Main()
{
    Application.Run(new StepByStep1_11());
}

6.
Set the form as the startup object. Run the project and click on the form surface with the left and right mouse buttons. You see the form respond to the MouseDown event by displaying a message box.


The result of Step by Step 1.11 is similar to the result of Step by Step 1.9, in which you handle an event by attaching a delegate to it. Only the implementation is different.

What makes the code in Step by Step 1.11 work? It works because the OnMouseDown() method (similar to other On methods) is the core method that is invoked when the mouse button is pressed. This method is responsible for notifying all registered objects about the MouseDown event. This method is not new; it was in place and working hard even when you were using the delegate-based event- handling scheme. How is that possible when you didn't code the method in your earlier programs? Recall from the section “Using Visual Inheritance” that the derived class inherits all members from its base classes in its inheritance tree. Step by Step 1.11 gets the OnMouseDown event from the Control class. In the base class Control, the OnMouseDown() method is declared as follows:

protected virtual void OnMouseDown(
  System.Windows.Forms.MouseEventArgs e);

Because the method is protected, it is available in all classes derived from Control, such as a Form and the delegate-based event-handling form StepByStep1_9. This method actually invokes the calls to delegates when the event takes place. The event-handling scheme discussed earlier keeps that fact hidden from you for the sake of simplicity.

The virtual modifier in the original declaration means that if the derived classes are not satisfied by the definition of this method in the original base class and if they need to extend it, they can do so by overriding its definition. That's what you do in Step by Step 1.11. When you override the method in a derived class, its base class version is not called. Instead, the overriding member in the most-derived class (which is StepByStep1_11 in this case) is called. That's how the version of the method that you write in Step by Step 1.11 is executed when the mouse button is pressed.

The sections “Handling Events by Attaching a Delegate” and “Handling Events by Overriding a Protected Method of a Base Class” discuss two schemes for event handling. Can these schemes exist together? To answer this question, try Step by Step 1.12.

STEP BY STEP

1.12 Mixing the Two Event Handling Schemes

1.
Open the project 316C01. In the Solution Explorer right-click the project name and select Add, Add Windows Form from the context menu. Name the new form StepByStep1_12 and click the Open button.

2.
Open the Properties window. Change the Text property of the form to Mixing Event Handling Techniques.

3.
Search for the MouseDown event, and double-click the row that contains the MouseDown event. Modify its event handler to look like this:

private void StepByStep1_12_MouseDown(object sender,
    System.Windows.Forms.MouseEventArgs e)
{
    MessageBox.Show(
      String.Format("X ={0}, Y={1}", e.X, e.Y),
      String.Format("The {0} mouse button hit me at:",
        e.Button.ToString()));
}

4.
Add the following code after the event handling code from step 3:

protected override void OnMouseDown(MouseEventArgs e)
{
    if (this.BackColor== Color.AntiqueWhite)
        this.BackColor = Color.LightCoral;
    else
        this.BackColor = Color.AntiqueWhite;
}
[STAThread]
static void Main()
{
    Application.Run(new StepByStep1_12());
}

5.
Set the form as the startup object and execute it. When you click the form area, the background color changes but the message box is not displayed.


It seems that in Step by Step 1.12 you do not achieve quite what you wanted to achieve. Don't the two event handling techniques coexist?

When you click the mouse button, only the event handler code written inside the OnMouseDown() method executes, and the other handler that is wired with the help of designer does not execute. That is because Step by Step 1.12 does not code the OnMouseDown() method properly. To understand the mistake, you need to take a look at how the OnMouseDown() method works in its original form, if you hadn't overridden it. Its base class version would look something like this:

public event MouseEventHandler MouseDown;
protected virtual void OnMouseDown(MouseEventArgs e)
{
    if (MouseDown != null)
     {
       //Invokes the delegates.
       MouseDown(this, e);
      }
   }
}

EXAM TIP

Overriding Protected Methods of a Base Class A derived class extends the functionality of its base class. It is generally a good idea to call the base class version of a method when you override a method in a derived class. That way, the derived class has at least the level of functionality offered by the base class. You can of course write more code in the overridden method to achieve extended functionality of the derived class.

On the other hand, if a derived class does not call the base class version of a method from an overridden method in derived class, you are not able to access all the functionality provided by the base class in the derived class.


The OnMouseDown() method is invoked when the mouse button is pressed. In its code, it checks whether the associated MouseDown event has a delegate list associated with it. If the list is not empty, it raises the MouseDown event that actually fires all attached event handlers with the help of their respective delegate objects. (Recall from earlier discussions that a delegate object holds a reference to the method name and can invoke it dynamically.)

In Step by Step 1.12 , because you override the definition of the OnMousedown() method, its old base class logic that used to call other event handlers no longer executes. As a result, the events added through the delegate list are not executed. How can you fix the problem? The solution to this problem also teaches you a good programming practice: You should call the base class implementation of the protected On method whenever you override it. The modified OnMouseDown() method in Step by Step 1.12 would look like this:

protected override OnMouseDown(MouseEventArgs e)
{
    //fixes the problem by also calling base
    //class version of OnMouseDown method
    base.OnMouseDown(e);
    if (this.BackColor== Color.AntiqueWhite)
        this.BackColor = Color.LightCoral;
    else
        this.BackColor = Color.AntiqueWhite;}

This modification allows the base class implementation of the OnMouseDown() method to be executed; this is the method where the delegates are processed.

REVIEW BREAK

  • Events allow a program to respond to changes in the code's environment.

  • Custom code can be executed when an event fires if the code is registered with the event. The pieces of code that respond to an event are called event handlers.

  • Event handlers are registered with events through delegate objects.

  • It is possible to respond to an event by overriding the On method corresponding to an event. When you use this method, you should be sure to call the corresponding On method for the base class so that you don't miss any of the event handlers registered through delegates when the event is raised.


..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.128.197.2