Normally, a user interacts with an app’s GUI to indicate the tasks that the app should perform. For example, when you write an e-mail in an e-mail app, clicking the Send button tells the app to send the e-mail to the specified e-mail addresses. GUIs are event driven. When the user interacts with a GUI component, the interaction—known as an event—drives the program to perform a task. Before GUIs, the program told the user what to do next. With GUIs, the user tells the program what to do. Common events (user interactions) that might cause an app to perform a task include
clicking a Button
,
typing in a TextBox
,
selecting an item from a menu,
closing a window and
moving the mouse.
All GUI controls have events associated with them. Objects of other types also can have associated events as well. A method that performs a task in response to an event is called an event handler, and the overall process of responding to events is known as event handling.
The Form
in the app of Fig. 14.5 contains a Button
that a user can click to display a MessageBox
. In line 6, notice the namespace
declaration, which is inserted for every class you create—we’ve been removing these from earlier simple examples. Namespaces organize groups of related classes. Recall from Section 7.4.3 that each class’s name is actually a combination of its namespace name, a dot (.
) and the class name—again, this is known as the class’s fully qualified name. We’ll use namespaces like this in Chapters 15 and 19. If another namespace also contains a class with the same name, the fully qualified class names must be used to distinguish between the classes in the app and prevent a name conflict (also called a name collision).
Form1.cs
FileUsing the techniques presented in Section 2.6, create a Form
containing a Button
. First, create a new Windows Form
s app names SimpleEventExample
. Then:
Rename the Form1.cs
file to SimpleEventExampleForm.cs
in the Solution Explorer.
Click the Form
in the designer, then use the Properties window to set the Form
’s Text
property to "Simple Event Example"
.
Set the Form
’s Font
property to Segoe UI, 9pt. To do so, select the Font
property in the Properties window, then click the ellipsis (…) button in the property’s value field to display a font dialog.
Button
to the Form
Drag a Button
from the Toolbox onto the Form
. In the Properties window, set the (Name)
property (which specifies the Button
’s variable name) to clickButton
and the Text
property to Click Me
. By convention, a control’s variable name ends with the control’s type. For example, in the variable name clickButton
, “Button
” is the control’s type.
Button
’s Click
EventWhen the user clicks the Button
in this example, we want the app to respond by displaying a MessageBox
. To do this, you must create an event handler for the Button
’s Click
event, which you can do by double clicking the Button
on the Form
. This opens the file containing the following empty event handler in the program code:
private void clickButton_Click(object sender, EventArgs e)
{
}
By convention, the IDE names the event-handler method as objectName_
eventName (e.g., clickButton_Click
). The clickButton_Click
event handler executes when the user clicks the clickButton
control.
Each event handler receives two parameters when it’s called. The first—an object
reference named sender
by default—is a reference to the object that the user interacted with to generate the event. The second is a reference to an EventArgs
object (or an object of an EventArgs
derived class), which is typically named e
. This object contains additional information about the event that occurred. EventArgs
is the base class of all classes that represent event information.
MessageBox
To display a MessageBox
in response to the event, insert the statement
MessageBox.Show("Button was clicked.");
in the event handler’s body. The resulting event handler appears in lines 18–21 of Fig. 14.5. When you execute the app and click the Button
, a MessageBox
appears displaying the text "Button was clicked."
.
Visual Studio places the auto-generated GUI code in the Form
class’s Designer.cs
file—in this example, the file SimpleEventExampleForm.Designer.cs
. You can open this file by expanding the Form
class’s node in the Solution Explorer window and double clicking the file name that ends with Designer.cs
. Figs. 14.6 and 14.7 show this file’s contents. The IDE collapses the code in lines 23–57 of Fig. 14.7 by default—you can click the
icon next to line 23 to expand the code, then click the
icon next to that line to collapse it.
Now that you have studied classes and objects in detail, this code will be easier to understand. Since this code is created and maintained by Visual Studio, you generally do not need to look at it. In fact, you do not need to understand most of the code shown here to build GUI apps. However, we now take a closer look to help you understand how GUI apps work.
The auto-generated code that defines the GUI is actually part of the Form
’s class—in this case, SimpleEventExampleForm
. Line 3 of Fig. 14.6 (and line 9 of Fig. 14.5) uses the
partial
modifier, which allows this class to be split among multiple files, including the files that contain auto-generated code and those in which you write your own code. Line 59 of Fig. 14.7 declares the clickButton
that we created in Design mode. It’s declared as an instance variable of class SimpleEventExampleForm
. By default, all variable declarations for controls created through C#’s design window have a private
access modifier. The code also includes the Dispose
method for releasing resources (Fig. 14.6, lines 14–21) and method InitializeComponent
(Fig. 14.7, lines 29–55), which contains the code that creates the Button
, then sets some of the Button
’s and the Form
’s properties. The property values correspond to the values set in the Properties window for each control. Visual Studio adds comments to the code that it generates, as in lines 33–35. Line 42 was generated when we created the event handler for the Button
’s Click
event.
Method InitializeComponent
is called when the Form
is created, and establishes such properties as the Form
title, the Form
size, control sizes and text. Visual Studio also uses the code in this method to create the GUI you see in design view. Changing the code in InitializeComponent
may prevent Visual Studio from displaying the GUI properly.
The code in the Designer.cs
file that’s generated by building a GUI in Design mode is not meant to be modified directly, which is why this code is placed in a separate file. Modifying this code can prevent the GUI from being displayed correctly in Design mode and might cause an app to function incorrectly. In Design mode, it’s recommended that you modify control properties only in the Properties window, not in the Designer.cs
file.
The control that generates an event is known as the event sender. An event-handling method—known as the event handler—responds to a particular event that a control generates. When the event occurs, the event sender calls its event handler to perform a task (i.e., to “handle the event”).
The .NET event-handling mechanism allows you to choose your own names for event-handling methods. However, each event-handling method must declare the proper parameters to receive information about the event that it handles. Since you can choose your own method names, an event sender such as a Button
cannot know in advance which method will respond to its events. So, we need a mechanism to indicate which method is the event handler for an event.
Event handlers are connected to a control’s events via special objects called delegates. A delegate type declaration specifies the return type and signature of a method—in event handling, the delegate specifies the return type and arguments for an event handler. GUI controls have predefined delegates that correspond to every event they can generate. For example, the delegate for a Button
’s Click
event is of type EventHandler
(namespace System
). The online help documentation declares this type as follows:
public delegate void EventHandler(object sender, EventArgs e);
This uses the delegate
keyword to declare a delegate type named EventHandler
, which can hold references to methods that return void
and receive two parameters—one of type object
(the event sender) and one of type EventArgs
. If you compare the delegate declaration with clickButton_Click
’s first line (Fig. 14.5, line 18), you’ll see that this event handler returns the same type and receives the same parameters specified by the EventHandler
delegate—the parameters’ names need not match. The preceding declaration actually creates an entire class for you. The details of this special class’s declaration are handled by the compiler.
Since each event handler is declared as a delegate, the event sender can simply call the appropriate delegate when an event occurs—a Button
calls the EventHandler
delegate that corresponds to its Click
event in response to a click. The delegate’s job is to invoke the appropriate method. To enable the clickButton_Click
method to be called, Visual Studio assigns clickButton_Click
to the click Button
’s Click EventHandler
delegate, as shown in line 42 of Fig. 14.7. This code is added by Visual Studio when you double click the Button
control in Design mode. The expression
new System.EventHandler(this.clickButton_Click);
creates an EventHandler
delegate object and initializes it with the clickButton_Click
method. Line 42 uses the +=
operator to add the delegate to the Button
’s Click Event-Handler
delegate. This enables clickButton_Click
to respond when a user clicks the Button
. The +=
operator is overloaded by the delegate class that’s created by the compiler.
You can actually specify that several methods should be invoked in response to one event by adding other delegates to the Button
’s Click
event with statements similar to line 42 of Fig. 14.7. Event delegates are multicast—they represent a set of delegate objects that all have the same signature. When an event occurs, the event sender calls every method referenced by the multicast delegate. This is known as event multicasting. Event delegates derive from class MulticastDelegate
, which derives from class Delegate
(both from namespace System
). For most cases, you’ll specify only one event handler for a particular event on a control.
For the GUI app in Fig. 14.5, you double clicked the Button
control on the Form
to create its event handler. This technique creates an event handler for a control’s default event—the event that’s most frequently used with that control. Controls can generate many different events, and each one can have its own event handler. For instance, your app also can provide an event handler for a Button
’s MouseHover
event, which occurs when the mouse pointer remains positioned over the Button
for a short period of time. We now discuss how to create an event handler for an event that’s not a control’s default event.
You can create event handlers through the Properties window. If you select a control on the Form
, then click the Events icon (the lightning bolt icon in Fig. 14.8) in the Properties window, that control’s events are listed in the window. You can double click an event’s name to display in the editor an existing event handler for that event, or to create the event handler if it does not yet exist in your code. You also can select an event, then use the drop-down list to its right to choose an existing method that should be used as the event handler for that event. The methods that appear in this drop-down list are the Form
class’s methods that have the proper signature to be an event handler for the selected event. You can return to viewing the properties of a control by selecting the Properties icon (Fig. 14.8).
A single method can handle events from multiple controls. For example, consider an app that displays CheckBox
es that represent bold and italic fonts. The user could select bold, italic or both. In this case, the font’s style depends on both CheckBox
es, so their events could be handled by the same method, which would determine each CheckBox
’s state to determine the user’s selected font style.
You can specify an event handler for multiple events by selecting multiple controls (drag over them, hold Shift and click each or hold Ctrl and click each) and selecting a single method in the Properties window’s Events tab. If you create a new event handler this way, you should rename it appropriately so that it does not contain one control’s name. You could also select each control individually and specify the same method for each one’s event.
Read the Visual Studio documentation to learn about the different events raised by each control. To do this, select a control in the IDE (either in your Form
’s design or in the Tool-box and press the F1 key to display that control’s online help (Fig. 14.9).
The web page that’s displayed contains basic information about the control’s class. In the left column of the page are several links to more information about the class—Button Methods, Button Properties, Button Events and Button Constructor. Each link displays a subset of the class’s members. Click the link to the list of events for that control (Button Events in this case) to display the supported events for that control.
Next, click the name of an event to view its description and examples of its use. We selected the Click
event to display the information in Fig. 14.10. The Click
event is a member of class Control
, an indirect base class of class Button
. The Remarks section of the page discusses the details of the selected event. Alternatively, you could use the Object Browser to look up this information in the System.Windows.Forms
namespace. The Object Browser shows only the members originally defined in a given class. The Click
event is originally defined in class Control
and inherited into Button
. For this reason, you must look at class Control
in the Object Browser to see the documentation for the Click
event. See Section 10.11 for more information regarding the Object Browser.