User:Foxall/04
Hour 4. Understanding Events
[wax ka badal]It's fairly easy to create an attractive interface for an application using C#'s integrated design tools. You can create beautiful forms that have buttons to click, text boxes in which to type information, picture boxes in which to view pictures, and many other creative and attractive elements with which users can interact. However, this is just the start of producing a C# program. In addition to designing an interface, you have to empower your program to perform actions in response to how a user interacts with the program and how Windows interacts with the program. This is accomplished by using events. In the previous hour, you learned about objects and their members�notably, properties and methods. In this hour, you'll learn about object events and event-driven programming, and you'll learn how to use events to make your applications responsive.
The highlights of this hour include the following:
- [file:///C:/Documents%20and%20Settings/dani/Asztal/c%23in24h/ch04lev1sec1.htm#ch04lev1sec1 Understanding event-driven programming]
- [file:///C:/Documents%20and%20Settings/dani/Asztal/c%23in24h/ch04lev1sec1.htm#ch04lev2sec1 Triggering events]
- [file:///C:/Documents%20and%20Settings/dani/Asztal/c%23in24h/ch04lev1sec1.htm#ch04lev2sec3 Avoiding recursive events]
- [file:///C:/Documents%20and%20Settings/dani/Asztal/c%23in24h/ch04lev1sec1.htm#ch04lev2sec4 Accessing an object's events]
- [file:///C:/Documents%20and%20Settings/dani/Asztal/c%23in24h/ch04lev1sec1.htm#ch04lev2sec5 Working with event parameters]
- [file:///C:/Documents%20and%20Settings/dani/Asztal/c%23in24h/ch04lev1sec2.htm#ch04lev2sec8 Creating event handlers]
- [file:///C:/Documents%20and%20Settings/dani/Asztal/c%23in24h/ch04lev1sec1.htm#ch04lev2sec4 Dealing with orphaned events]
Understanding Event-Driven Programming
[wax ka badal]With "traditional" programming languages (often referred to as procedural languages), the program itself fully dictates what code is executed and when it's executed. When you start such a program, the first line of code in the program executes, and the code continues to execute in a completely predetermined path. The execution of code may, on occasion, branch and loop, but the execution path is completely controlled by the program. This often meant that a program was rather restricted in how it could respond to the user. For instance, the program might expect text to be entered into controls on the screen in a predetermined order, unlike in Windows, where a user can interact with different parts of the interface, often in any order the user chooses.
graphics/newterm.gif | C# incorporates an event-driven programming model. Event-driven applications aren't bound by the constraints of procedural programs. Instead of the top-down approach of procedural languages, event-driven programs have logical sections of code placed within events. There is no predetermined order in which events occur, and often the user has complete control over what code is executed in an event-driven program by interactively triggering specific events, such as by clicking a button. An event, along with the code it contains, is called an event procedure. |
Triggering Events
In the previous hour, you learned how a method is simply a function of an object. Events are a special kind of method; they are a way for objects to signal state changes that may be useful to clients of that object. Events are methods that can be called in special ways�usually by the user interacting with something on a form or by Windows itself, rather than being called from a statement in your code.
There are many types of events and many ways to trigger those events. You've already seen how a user can trigger the Click event of a button by clicking it. User interaction isn't the only thing that can trigger an event, however. An event can be triggered in one of the following four ways:
- Users can trigger events by interacting with your program.
- Objects can trigger their own events, as needed.
- The operating system (whichever version of Windows the user is running) can trigger events.
- You can trigger events by calling them using C# code.
Events Triggered Through User Interaction
The most common way an event is triggered is by a user interacting with a program. Every form, and almost every control you can place on a form, has a set of events specific to its object type. For example, the Button control has a number of events, including the Click event, which you've already used in previous hours. The Click event is triggered, and then the code within the Click event executes when the user clicks the button.
The Textbox control allows users to enter information using the keyboard, and it also has a set of events. The Textbox control has some of the same types of events as the Button control, such as a Click event, but the Textbox control also has events not supported by the Button control, such as a TextChanged event. The TextChanged event occurs each time the contents of the text box change, such as when the user types information into the text box. Because you can't enter text within a Button control, it makes sense that the Button control wouldn't have a TextChanged event. Each and every object that supports events supports a unique set of events.
Each type of event has its own behavior, and it's important to understand the events with which you work. The TextChanged event, for instance, exhibits a behavior that may not be intuitive to a new developer because the event fires each time the contents of the text box change. If you were to type the following sentence into an empty text box:
C# is very cool!
the Change event would be triggered 16 times�once for each character typed�because each time you enter a new character, the contents of the text box are changed. Although it's easy to think that the Change event fires only when you commit your entry, such as by leaving the text box or pressing Enter, this is simply not how it works. Again, it's important to learn the nuances and the exact behavior of the events you're using. If you use events without fully understanding how they work, your program may exhibit unusual, and often very undesirable, results.
graphics/bookpencil.gif | Triggering events (which are just a type of procedure) using C# code is discussed in detail in [file:///C:/Documents%20and%20Settings/dani/Asztal/c%23in24h/ch11.htm#ch11 Hour 11], "Creating and Calling Methods." |
Events Triggered by an Object
Sometimes an object triggers its own events. The most common example of this is the Timer control's Timer event. The Timer control doesn't appear on a form when the program is running; it appears only when you're designing a form. The Timer control's sole purpose is to trigger its Timer event at an interval that is specified in its Interval property.
By setting the Timer control's Interval property, you control the interval, in milliseconds, when the Timer event executes. After firing its Timer event, a Timer control resets itself and again fires its Timer event when the interval has passed. This occurs until the interval is changed, the Timer control is disabled, or the Timer control's form is unloaded. A common use of timers is to create a clock on a form. You can display the time in a label and update the time at regular intervals by placing the code to display the current time in the Timer event. You'll create a project with a Timer control in [file:///C:/Documents%20and%20Settings/dani/Asztal/c%23in24h/ch08.htm#ch08 Hour 8], "Advanced Controls."
Events Triggered by the Operating System
Finally, Windows can trigger certain events within your program �events that you may not even know exist. For example, when a form is fully or partially obstructed by another window, the program needs to know when the offending window is resized or moved so that it can repaint the area of its window that's been hidden. Windows and C# work together in this respect. When the obstructing window is moved or resized, Windows tells C# to repaint the form, which C.htm# does. This also causes C# to raise the form's Paint event. You can place code into the Paint event to create a custom display for the form, such as drawing shapes on the form using a Graphics object. That way, every time the form repaints itself, your custom drawing code executes.
Avoiding Recursive Events
graphics/newterm.gif | You must make sure never to cause an event to endlessly trigger itself. An event that continuously triggers itself is called a recursive event. To illustrate a situation that causes a recursive event, think of the text box's TextChanged event discussed earlier. The TextChanged event fires every time the text within the text box changes. Placing code into the TextChanged event that alters the text within the text box would cause the Change event to be fired again, which could result in an endless loop. Recursive events terminate when Windows returns a StackOverFlow exception (see [file:///C:/Documents%20and%20Settings/dani/Asztal/c%23in24h/04.htm#ch04fig01 Figure 4.1]), indicating that Windows no longer has the resources to follow the recursion. |
graphics/bulb.gif | When you receive a StackOverFlow exception, you should look for a recursive event as the culprit. |
Recursive events can involve more than one event in the loop. For example, if Event A triggers Event B, which in turn triggers Event A, you can have recursion of the two events. Recursion can take place among a sequence of many events, not just one or two.
graphics/bookpencil.gif | Uses for recursive procedures actually exist, such as when you are writing complex math functions. For instance, recursive events are often used to compute factorials. However, when you purposely create a recursive event, you must ensure that the recursion isn't infinite. |
Accessing an Object's Events
Accessing an object's events is simple, and if you've been following the examples in this book, you've already accessed a number of objects' default events. To access all of an object's events, you can use the Events icon (the lightning bolt) in the Properties window.
You're now going to create a project to get the feel for working with events. Start C# and create a new Windows Application project titled View Events, and then follow these steps:
- Use the toolbox to add a picture box to the form.
- Change the name of the picture box to picText.
- Click the Events button on the Properties window toolbar (the lightning bolt icon).
Your screen should look like the one in [file:///C:/Documents%20and%20Settings/dani/Asztal/c%23in24h/04.htm#ch04fig02 Figure 4.2]. Notice that the Properties window now lists all the events for the selected object; in your case, it is the picText PictureBox object.
When you access a control's events, the default event for that type of control is selected. As you can see, the Click event is the default for a PictureBox. Scroll through the picText events and select the MouseDown event. Double-click the word MouseDown and C# will create the MouseDown event procedure and position you within it, ready to enter code (see [file:///C:/Documents%20and%20Settings/dani/Asztal/c%23in24h/04.htm#ch04fig03 Figure 4.3]).
graphics/newterm.gif | The code statement above the cursor is the event declaration. An event declaration is a statement that defines the structure of an event handler. Notice that this event declaration contains the name of the object, an underscore character (_), and then the event name. Following the event name is a set of parentheses. The items within the parentheses are called parameters, which is the topic of the next section. This is the standard declaration structure for an event procedure. |
The full event declaration for the Click event is the following:
private void picText_MouseDown(object sender, _ System.Windows.Forms.MouseEventArgs e)
graphics/bookpencil.gif | The words Private and Void are reserved words that indicate the scope and type of the method. Scope and type are discussed in [file:///C:/Documents%20and%20Settings/dani/Asztal/c%23in24h/ch11.htm#ch11 Hour 11]. |
Working with Event Parameters
graphics/newterm.gif | As mentioned previously, the items within the parentheses of an event declaration are called parameters. An event parameter is a variable that is created and assigned a value by C#. These parameter variables are used to get, and sometimes set, relevant information within the event. Multiple parameters within an event procedure are always separated by commas. A parameter contains data that relates to the event. This data may be a number, text, an object�almost anything. As you can see, the MouseDown event has two parameters. When the Click event procedure is triggered, C# automatically creates the parameter variables and assigns them values for use in this one execution of the event procedure; the next time the event procedure occurs, the values in the parameters are reset. You use the values in the parameters to make decisions or perform operations in your code. |
The MouseDown event of a form has the following parameters:
object sender
and
System.Windows.Forms.MouseEventArgs e
The first word identifies the type of data the parameter contains, followed by the name of the parameter. The first parameter, sender, holds a generic object. Object parameters can be any type of object supported by C#. It's not critical that you understand data types right now, just that you're aware that different parameter variables contain different types of information. Some contain text, others contain numbers, and still others (many others) contain objects. In the case of the sender parameter, it will always hold a reference to the control causing the event.
graphics/newterm.gif | The sender parameter returns a reference to the control that causes the event. It's often best to use the sender parameter rather than referencing the control by name, so that if you change the name of the control, you won't have to update the code. Also, by referencing the sender object, the code becomes portable; you can copy and paste it into the event of a different control of the same type, and the code should work without modification. |
The e parameter, on the other hand, is where the real action is with the MouseDown event. The e parameter also holds an object; in this case the object is of the type System.WinForms.MouseEventArgs. This object has properties that relate to the MouseDown_event. To see them, type in the following code, but don't press anything after entering the dot (period):
e.
When you press the period, you'll get a drop-down list showing you the members (properties and methods) of the e object (see [file:///C:/Documents%20and%20Settings/dani/Asztal/c%23in24h/04.htm#ch04fig04 Figure 4.4]). Using the e object, you can determine a number of things about the occurrence of the MouseDown event. I've listed some of the more interesting items in [file:///C:/Documents%20and%20Settings/dani/Asztal/c%23in24h/04.htm#ch04table01 Table 4.1].
Property | Description |
Clicks | Returns the number of times the user clicked the mouse button. |
Button | Returns the button that was clicked (left, middle, right). |
X | Returns the horizontal coordinate at which the pointer was located when the user clicked. |
Y | Returns the vertical coordinate at which the pointer was located when the user clicked. |
graphics/bookpencil.gif | Each time the event occurs, the parameters are initialized by C# so that they always reflect the current occurrence of the event. |
Each event has parameters specific to it. For instance, the TextChanged event returns parameters different from the MouseDown event. As you work with events�and you'll work with a lot of events�you'll quickly become familiar with the parameters of each event type. You'll learn how to create parameters for your own methods in [file:///C:/Documents%20and%20Settings/dani/Asztal/c%23in24h/ch11.htm#ch11 Hour 11].
Deleting an Event Handler
Deleting an event handler involves more than just deleting the event procedure. When you add a new event handler to a class, C# automatically creates the event procedure for you and positions you to enter code within the event. However, C# does a little bit more for you "under the covers" to hook the event procedure to the control. It does this by creating a code statement in the hidden code of the class. Ordinarily, you don't have to worry about this statement. However, when you delete an event procedure, C# doesn't automatically delete the hidden code statement, and your code won't compile. The easiest way to correct this is to run the project; when C# encounters the error, it will show you the offending statement, which you can delete. Try this now:
- Delete the MouseDown procedure (don't forget to delete the open and close brackets of the procedure, as well as any code within them). This deletes the procedure.
- Press F5 to run the project. You'll receive a message that a build error has occurred. Click No to return to the code editor.
- A task for the error has been created in the Task List. Double-click the task and C# will take you to the offending statement. It will read:
this.pictureBox1.MouseDown += new System.Windows.Forms.MouseEventHandler(this.pictureBox1_MouseDown);
- Delete this statement, and now your code will compile and run.
Whenever you delete an event procedure, you will have to delete the corresponding statement that links the procedure to its object before the code will run.
Building an Event Example Project
You're now going to create a very simple project in which you'll use the event procedures of a text box. Specifically, you're going to write code to display a message when a user presses a mouse button on the text box, and you'll write code to clear the text box when the user releases the button. You'll be using the e parameter to determine which button the user has pressed.
Creating the User Interface
Create a new Windows application titled Events Example. Change the form's Text property to Events Demo.
Next, add a text box to the form by double-clicking the TextBox tool in the toolbox. Set the properties of the text box as follows:
Property | Value |
Name | txtEvents |
Location | 48,120 |
Size | 193,20 |
Text | Click Me! |
The only other control you need on your form is a label. Label controls are used to display static text; users cannot type text into a label. Add a new label to your form now by double-clicking the Label tool in the toolbox and then setting the Label control's properties as follows:
Property | Value |
Name | lblMessage |
Location | 48,152 |
Size | 192,16 |
Text | (make blank) |
TextAlign | MiddleCenter |
Your form should now look like the one in [file:///C:/Documents%20and%20Settings/dani/Asztal/c%23in24h/04.htm#ch04fig05 Figure 4.5]. It's a good idea to save frequently, so save your project now by clicking the Save All button on the toolbar.
Creating Event Handlers
The interface for the Events Example project is complete�on to the fun part. You're now going to create the event procedures that empower your program to do something. The event that we're interested in first is the MouseDown event. Select the TextBox on your design form, and then click the Events icon on the Properties window toolbar.
The default event for text boxes is the TextChanged event, so it's the one now selected. You're not interested in the TextChanged event at this time, however. Scroll through the event list for the MouseDown event. Double-click MouseDown; C# then creates a new MouseDown event procedure for the text box (see [file:///C:/Documents%20and%20Settings/dani/Asztal/c%23in24h/04.htm#ch04fig06 Figure 4.6]).
Enter the following code into the MouseDown event procedure:
switch(e.Button) { case MouseButtons.Left: lblMessage.Text = "You are pressing the left button!"; break; case MouseButtons.Right: lblMessage.Text = "You are pressing the right button!"; break; case MouseButtons.Middle: lblMessage.Text = "You are pressing the middle button!"; break; }
The Switch construct, which is discussed in detail in [file:///C:/Documents%20and%20Settings/dani/Asztal/c%23in24h/ch14.htm#ch14 Hour 14], "Making Decisions in C# Code," compares the value of an expression to a list of possible values. In this instance, the expression is the value of e.Button (the Button property of the object e). When this code executes, the expression is compared to each Case statement in the order in which the statements appear. If and when a match is found, the code immediately following the Case statement that was matched gets executed. Therefore, the code you wrote looks at the value of e.Button and compares it to three values, one at a time. When the Switch construct determines which button has been pressed, it displays a message about it in the Label control.
graphics/bookpencil.gif | In a more robust application, you would probably perform more useful and more complicated code. For instance, you may want to display a custom pop-up menu when the user clicks with the right button and execute a specific function when the user clicks with the middle button. All this is possible, and more. |
The nice thing about objects is that you don't have to commit every detail about them to memory. For example, you don't need to memorize the return values for each type of button (who wants to remember MouseButtons.Left anyway?). Just remember that the e parameter contains information about the event. When you type e and press the period, the IntelliSense drop-down list appears and shows you the members of e, one of which is Button.
Don't feel overwhelmed by all the object references you'll encounter throughout this book. Simply accept that you can't memorize them all, nor do you need to; you'll learn the ones that are important, and you'll use Help when you're stuck. Also, after you know the parent object in a situation, such as the e object in this example, it's easy for you to determine the objects and members that belong to it by using the IntelliSense drop-down lists.
You're now going to add code to the MouseUp event to clear the label's Text property when the user releases the button. First, you'll need to create the MouseUp event procedure. To do this, return to the Form Design view (click the Form1.cs[Design] tab). The Properties should still have the txtEvents object's events listed. If the events aren't shown in the Properties window, select txtEvents from the drop-down list box in the Properties window and click the events icon. Locate and double-click the MouseUp event from the events list.
All you're going to do in the MouseUp_event is clear the label. Enter the following code:
lblMessage.Text = "";
Testing Your Events Project
Run your project now by pressing F5. If you entered all the code correctly and you don't receive any errors, your form will be displayed as shown in [file:///C:/Documents%20and%20Settings/dani/Asztal/c%23in24h/04.htm#ch04fig07 Figure 4.7].
graphics/bookpencil.gif | Remember that C# is case sensitive. Entering only one character in the wrong case will cause your project to fail to compile. |
Click the text box with the left mouse button and watch the label. It will display a sentence telling you which button has been clicked. When you release the button, the text is cleared. Try this with the middle and right buttons, as well. When you click the text box with the right button, Windows displays the standard shortcut menu for text boxes. When this menu appears, you have to select something from it or click somewhere off the menu to trigger the MouseUp event. In [file:///C:/Documents%20and%20Settings/dani/Asztal/c%23in24h/ch09.htm#ch09 Hour 9], "Adding Menus and Toolbars to Forms," you'll learn how to add your own shortcut menus to forms and controls. When you're satisfied that your project is behaving as it should, from the Debug menu choose Stop Debugging to stop the project (or click the Close button on your form), and then save your work by clicking Save All on the toolbar.
Summary
In this hour, you learned about event-driven programming, including what events are, how to trigger events, and how to avoid recursive events. In addition, you've learned how to access an object's events and how to work with parameters. Much of the code you'll write will execute in response to an event of some kind. By understanding how events work, including being aware of the available events and their parameters, you'll be able to create complex C# programs that react to a multitude of user and system input.
Q&A
[file:///C:/Documents%20and%20Settings/dani/Asztal/c%23in24h/04.htm#qad1e14038 Q1:] | Is it possible to create custom events for an object? |
A1: | You can create custom events for objects created from your custom classes (see [file:///C:/Documents%20and%20Settings/dani/Asztal/c%23in24h/ch17.htm#ch17 Hour 17], "Designing Objects with Classes"), but you cannot create custom events for existing C# objects such as forms and controls (without using some seriously advanced object-oriented techniques that are beyond the scope of this book). |
[file:///C:/Documents%20and%20Settings/dani/Asztal/c%23in24h/04.htm#qad1e14064 Q2:] | Is it possible for objects that don't have an interface to support events? |
A2: | Yes. However, to use the events of such an object, the object variable must be dimensioned a special way or the events aren't available. This gets a little tricky and is beyond the scope of this book. If you have an object in code that supports events, look in Help for the keyword WithEvents for information on how to use such events. |
> |
Workshop
The Workshop is designed to help you anticipate possible questions, review what you've learned, and get you thinking about how to put your knowledge into practice. The answers to the quiz are in [file:///C:/Documents%20and%20Settings/dani/Asztal/c%23in24h/app01.htm#app01 Appendix A],"Answers to Quizzes/Exercises."
Quiz
[file:///C:/Documents%20and%20Settings/dani/Asztal/c%23in24h/app01lev1sec4.htm#ch04ans01 1:] | Name three things that can cause events to occur. |
[file:///C:/Documents%20and%20Settings/dani/Asztal/c%23in24h/app01lev1sec4.htm#ch04ans02 2:] | True or False: All objects support the same set of events. |
[file:///C:/Documents%20and%20Settings/dani/Asztal/c%23in24h/app01lev1sec4.htm#ch04ans03 3:] | What is the default event type for a button? |
[file:///C:/Documents%20and%20Settings/dani/Asztal/c%23in24h/app01lev1sec4.htm#ch04ans04 4:] | The act of an event calling itself in a loop is called what? |
[file:///C:/Documents%20and%20Settings/dani/Asztal/c%23in24h/app01lev1sec4.htm#ch04ans05 5:] | What is the easiest way to access a control's default event handler? |
[file:///C:/Documents%20and%20Settings/dani/Asztal/c%23in24h/app01lev1sec4.htm#ch04ans06 6:] | All control events pass a reference to the control causing the event. What is the name of the parameter that holds this reference? |
Exercises
- Create a project with a single text box. In the Resize event of the form, show the Width of the form in the text box.
- Create a project with a form and a text box. Add code to the TextChange event to cause a recursion when the user types in text. Hint: Concatenate a character to the end of the user's text using a statement such as txtMyTextBox.Text = String. Concat(this. txtMyTextBox.Text,"a");
[file:///C:/Documents%20and%20Settings/dani/Asztal/c%23in24h/ch04lev1sec4.htm Previous Section] [file:///C:/Documents%20and%20Settings/dani/Asztal/c%23in24h/part02.htm ] |
[file:///C:/Documents%20and%20Settings/dani/Asztal/c%23in24h/04.htm#toppage Top] |