- •brief contents
- •about this book
- •The Windows Forms namespace
- •Part 1: Hello Windows Forms
- •Part 2: Basic Windows Forms
- •Part 3: Advanced Windows Forms
- •Who should read this book?
- •Conventions
- •Action
- •Result
- •Source code downloads
- •Author online
- •acknowledgments
- •about .NET
- •Casting the .NET
- •Windows Forms overview
- •about the cover illustration
- •Hello Windows Forms
- •1.1 Programming in C#
- •1.1.1 Namespaces and classes
- •1.1.2 Constructors and methods
- •1.1.3 C# types
- •1.1.4 The entry point
- •1.1.5 The Application class
- •1.1.6 Program execution
- •1.2 Adding controls
- •1.2.1 Shortcuts and fully qualified names
- •1.2.2 Fields and properties
- •1.2.3 The Controls property
- •1.3 Loading files
- •1.3.1 Events
- •1.3.2 The OpenFileDialog class
- •1.3.3 Bitmap images
- •1.4 Resizing forms
- •1.4.1 Desktop layout properties
- •1.4.2 The Anchor property
- •1.4.3 The Dock property
- •1.5 Recap
- •2.1 Programming with Visual Studio .NET
- •2.1.1 Creating a project
- •Action
- •Result
- •2.1.2 Executing a program
- •Action
- •Result
- •2.1.3 Viewing the source code
- •View the code generated by Visual Studio .NET
- •Action
- •Result
- •2.2 Adding controls
- •2.2.1 The AssemblyInfo file
- •Action
- •Results
- •2.2.2 Renaming a form
- •Action
- •Result
- •2.2.3 The Toolbox window
- •Action
- •Result
- •2.3 Loading files
- •2.3.1 Event handlers in Visual Studio .NET
- •Action
- •Result
- •2.3.2 Exception handling
- •Action
- •Result
- •Action
- •Results and Comments
- •2.4 Resizing forms
- •2.4.1 Assign the Anchor property
- •Action
- •Result
- •2.4.2 Assign the MinimumSize property
- •Action
- •Result
- •2.5 Recap
- •Basic Windows Forms
- •Menus
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •3.3 Click events
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •3.5 Context menus
- •Action
- •Result
- •Action
- •Result
- •3.6 Recap
- •Status bars
- •4.1 The Control class
- •4.2 The StatusBar class
- •Action
- •Result
- •Action
- •Result
- •4.3.1 Adding panels to a status bar
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •4.5 Recap
- •Reusable libraries
- •5.1 C# classes and interfaces
- •5.2 Class libraries
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •5.3 Interfaces revisited
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •5.4 Robustness issues
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Common file dialogs
- •Action
- •Results
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •6.3 Paint events
- •Action
- •Result
- •Action
- •Result
- •6.4 Context menus revisited
- •Action
- •Result
- •Action
- •Result
- •6.5 Files and paths
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •6.6 Save file dialogs
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •6.7 Open file dialogs
- •Action
- •Result
- •Action
- •Result
- •6.8 Recap
- •Drawing and scrolling
- •7.1 Form class hierarchy
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •7.4 Panels
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Dialog boxes
- •8.1 Message boxes
- •Action
- •Result
- •Action
- •Result
- •8.1.4 Creating A YesNoCancel dialog
- •Action
- •Result
- •Action
- •Result
- •8.2 The Form.Close method
- •8.2.1 The relationship between Close and Dispose
- •Action
- •Result
- •8.3 Modal dialog boxes
- •Action
- •Result
- •Action
- •Result
- •8.3.2 Preserving caption values
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Basic controls
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •9.1.2 Creating a derived form
- •Action
- •Result
- •9.2 Labels and text boxes
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •9.3.6 Adding AlbumEditDlg to our main form
- •Action
- •Result
- •Action
- •Result
- •9.4 Recap
- •List controls
- •10.1 List boxes
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •10.2 Multiselection list boxes
- •10.2.1 Enabling multiple selection
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •10.3 Combo boxes
- •Action
- •Result
- •Action
- •Result
- •10.4 Combo box edits
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •10.5 Owner-drawn lists
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •More controls
- •Action
- •Result
- •Action
- •Result
- •11.2 Tab pages
- •Action
- •Result
- •Action
- •Result
- •11.3.1 Dates and times
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •11.5 Recap
- •A .NET assortment
- •12.1 Keyboard events
- •Action
- •Result
- •Action
- •Result
- •12.2 Mouse events
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •12.3 Image buttons
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •12.4 Icons
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •12.5 Recap
- •Toolbars and tips
- •13.1 Toolbars
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •13.4.2 Creating tool tips
- •Action
- •Result
- •Action
- •Result
- •Advanced Windows Forms
- •List views
- •14.2 The ListView class
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •14.2.3 Populating a ListView
- •Action
- •Result
- •Action
- •14.3 ListView columns
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •14.6 Recap
- •Tree views
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •15.3 Dynamic tree nodes
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •15.4 Node selection
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •15.5 Fun with tree views
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Multiple document interfaces
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •16.3 Merged menus
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •16.4 MDI children
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •16.5 MDI child window management
- •Action
- •Result
- •Action
- •Result
- •16.6 Recap
- •Data binding
- •17.1 Data grids
- •Action
- •Result
- •Action
- •Result
- •17.2 Data grid customization
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Odds and ends .NET
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •18.2 Timers
- •Action
- •Result
- •Action
- •Result
- •18.3 Drag and drop
- •Action
- •Result
- •Action
- •Result
- •18.4 ActiveX controls
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •18.5 Recap
- •C# primer
- •A.1 C# programs
- •A.1.1 Assemblies
- •A.1.2 Namespaces
- •A.2 Types
- •A.2.1 Classes
- •A.2.2 Structures
- •A.2.3 Interfaces
- •A.2.4 Enumerations
- •A.2.5 Delegates
- •A.3 Language elements
- •A.3.1 Built-in types
- •A.3.2 Operators
- •A.3.3 Keywords
- •A.4 Special features
- •A.4.1 Exceptions
- •A.4.2 Arrays
- •A.4.3 Main
- •A.4.4 Boxing
- •A.4.5 Documentation
- •.NET namespaces
- •B.1 System.Collections
- •B.2 System.ComponentModel
- •B.3 System.Data
- •B.4 System.Drawing
- •B.5 System.Globalization
- •B.6 System.IO
- •B.7 System.Net
- •B.8 System.Reflection
- •B.9 System.Resources
- •B.10 System.Security
- •B.11 System.Threading
- •B.12 System.Web
- •B.13 System.Windows.Forms
- •B.14 System.XML
- •Visual index
- •C.1 Objects
- •C.2 Marshal by reference objects
- •C.3 Components
- •C.4 Common dialogs
- •C.7 Event data
- •C.8 Enumerations
- •For more information
- •bibliography
- •Symbols
- •Index
3.4.1DEFINING A SHARED HANDLER
The submenu for the Image menu item pops up whenever the Image menu is clicked. Our submenu items are selected by the user to control how the image should appear in the window. To implement this behavior, we will alter the SizeMode property of our PictureBox control depending on which menu was selected. The SizeMode values for these menus are as follows
The SizeMode settings for the Image submenu items
MenuItem |
SizeMode Setting |
Description |
|
|
|
Stretch to Fit |
StretchImage |
As we have already seen, this value causes the image to |
|
|
be stretched or shrunk to exactly fit the display area. |
Actual Size |
Normal |
This displays the actual image data in the display area with |
|
|
the upper left corner of the image in the upper left corner |
|
|
of the display area. |
|
|
|
One way to implement this behavior would be to handle the Click event for each MenuItem in the preceding table, and modify the SizeMode setting appropriately in each handler. A fine idea, but not our approach. Instead, this is a great opportunity to see the power of event handlers in .NET, not to mention lay the groundwork for some features we will explore later in this chapter and in other chapters.
For our implementation, we will use a single event handler for both MenuItem objects. This handler will also be employed when we discuss context menus later in the chapter, and will ensure consistency between our menu bar and context menu as we add more features in future chapters. To facilitate this amazing behavior, we will define a new structure to hold the SizeMode value depending on the Index setting of the menu.
Set the version number of the application to 3.4.
|
|
DEFINE ARRAY FOR SIZEMODE SETTINGS |
|
|
|
|
|
|
Action |
|
Result |
|
|
|
|
1 |
Locate the MainForm |
|
|
|
constructor in the |
|
|
|
MainForm.cs window. |
|
|
|
|
|
|
POPUP EVENTS AND SHARED HANDLERS |
89 |
DEFINE ARRAY FOR SIZEMODE SETTINGS (continued)
2 |
Add a private array of |
/// <summary> |
|
PictureBoxSizeMode |
/// Mode settings for the View->Image submenu. |
|
values called modeMenu- |
/// The order here must correspond to the order |
|
/// of menus in the submenu. |
|
|
Array just before the |
|
|
/// </summary> |
|
|
constructor. |
private PictureBoxSizeMode[] modeMenuArray = |
|
|
{ |
|
|
PictureBoxSizeMode.StretchImage, |
|
|
PictureBoxSizeMode.Normal |
|
|
}; |
|
|
Note: To enter the comment preceding the array defini- |
|
|
tion, type in three slashes (///)in Visual Studio and it |
|
|
will automatically expand to a <summary> comment |
|
|
block. |
|
|
|
3 |
Add a private integer |
private int _selectedImageMode = 0; |
|
_selectedImageMode after |
Note: This variable will hold the currently selected dis- |
|
the array. |
play mode for the image. |
|
|
|
With these variables available, a Click handler for both the menuStretch and menuActual menu items can now be implemented. One possible implementation for this handler is shown below:
// An example (not our approach) of a shared event handler
protected void menuImage_ChildClick (object sender, System.EventArgs e)
{
if (sender == (object)menuStretch)
{
// Code for Stretch to Window click
}
else
{
// Code for Actual Size click
}
}
This implementation uses the sender parameter provided to the handler to identify which menu was selected. This is an excellent idea and would work just fine. Because all classes ultimately derive from object, you can compare the sender parameter to your window control variables in order to identify which control raised the event. This is a common tactic used to handle a set of menus with a shared implementation.
In order to provide even more flexibility, we will favor an implementation that is not based on a comparison such as that shown here. This will allow us to modify our menus without the need to modify the code for this handler.
If you recall, the order of the menus within the parent menu menuImage is set using the Index property. The value of this property can be used as an index into the modeMenuArray variable to locate the proper SizeMode value.
90 |
CHAPTER 3 MENUS |
Since our handler is not specific to any one item, we will call the handler menuImage_ChildClick. Let’s create the code required before we discuss this further. This code continues the previous steps that created the variables used by this handler.
.
|
ADD SHARED CLICK HANDLER FOR IMAGE SUBMENU |
|
|
|
|
|
Action |
Result |
|
|
|
4 |
In the MainForm.cs |
|
|
[Design] window, add a |
|
|
Click event handler for the |
|
|
Stretch to Fit menu called |
|
|
menuImage_ChildClick. |
|
|
How-to |
|
|
a. Display the Properties |
|
|
window for the Stretch to |
|
|
Fit menu. |
|
|
b. Click the Events button to |
The new method is registered with the menuStretch object |
|
show the list of events. |
in the InitializeComponent method of the MainForm.cs |
|
c. Click the space to the |
|
|
source file: |
|
|
right of the Click item. |
|
|
menuStretch.Click += |
|
|
d. Enter the handler |
|
|
new System.EventHandler ( |
|
|
“menuImage_ChildClick” |
|
|
this.menuImage_ChildClick); |
|
|
by hand. |
The MainForm.cs code window is shown with the cursor at |
|
e. Press the Enter key. |
the beginning of this new method. |
|
|
protected void menuImage_ChildClick |
|
|
(object sender, System.EventArgs e) |
|
|
{ |
|
|
} |
|
|
|
5 |
Add this method as the |
The selected handler is registered with the Actual Size menu in |
|
Click handler for the |
the InidializeComponent method of the MainForm.cs |
|
Actual Size menu as well. |
source file. |
|
How-to |
menuActual.Click += |
|
a. Display the events for the |
new System.EventHandler ( |
|
this.menuImage_ChildClick); |
|
|
Actual Size menu. |
|
|
|
|
|
b. Click to the right of the |
|
|
Click item. |
|
|
c. Click the down arrow. |
|
|
d. Select the menuImage_ |
|
|
ChildClick event han- |
|
|
dler from the list. |
|
|
Note: This down arrow is |
|
|
shown in the graphic for |
|
|
the prior step. Clicking this |
|
|
arrow displays a list of pos- |
|
|
sible event handlers from |
|
|
your code. |
|
|
|
|
POPUP EVENTS AND SHARED HANDLERS |
91 |
We now have one event handler that receives the Click event for two different menus. Note how the handler is registered for each menu in the same way as our previous Click handlers.
Continuing with our previous steps, we can now implement this handler.
IMPLEMENT THE MENUIMAGE_CHILDCLICK EVENT HANDLER.
|
Action |
Result |
|
|
|
6 |
First, make sure sender is |
protected void menuImage_ChildClick |
|
a MenuItem object. |
(object sender, System.EventArgs e) |
|
|
{ |
|
|
if (sender is MenuItem) |
|
|
{ |
|
|
Note: Readers familiar with C# will recognize that this |
|
|
implementation requires two casts, one to perform the |
|
|
is statement, another to cast the sender parameter to |
|
|
a MenuItem object. This can be avoided using the as |
|
|
keyword, which we will discuss later in the book. |
|
|
|
7 |
Create a local MenuItem |
MenuItem mi = (MenuItem)sender; |
|
instance from sender. |
|
|
|
|
8 |
Set the SizeMode |
_selectedImageMode = mi.Index; |
|
property to the appropriate |
pbxPhoto.SizeMode = modeMenuArray[mi.Index]; |
|
array value based on the |
|
|
selected menu. |
|
|
|
|
9 |
Invalidate the PictureBox |
pbxPhoto.Invalidate(); |
|
control to redisplay the |
} |
|
image. |
} |
|
|
|
|
|
|
The code for the menuImage_ChildClick handler introduces a few new concepts. We duplicate it here so we can discuss it in more detail.
protected void menuImage_ChildClick (object sender, System.EventArgs e)
{
if (sender is MenuItem) |
b Verify sender is MenuItem object |
||
{ |
|
c Downcast sender to MenuItem instance |
|
MenuItem mi = (MenuItem)sender; |
|||
_selectedImageMode = mi.Index; |
|
d Assign new |
|
|
|||
pbxPhoto.SizeMode = modeMenuArray[mi.Index]; |
display settings |
||
pbxPhoto.Invalidate(); |
e Invalidate |
|
|
} |
PictureBox |
|
|
} |
control |
|
Let’s look at the new concepts introduced here:
bIn C++, there is no built-in mechanism for knowing if a variable is a certain type, making it difficult to safely downcast a variable from a base class (such as object) to a derived class (such as MenuItem). In C#, the is keyword provides a way to check that an object (such as the sender parameter) is in fact a specific type (in this case, a MenuItem instance).
92 |
CHAPTER 3 MENUS |
cThe key to this code is the ability to treat sender as a MenuItem object. The Index property is not available in the object class, so we need to convert our variable of type object into a variable of type MenuItem. Since the conversion is “down” the class hierarchy, such a conversion is called a downcast. In C++ such operations are dangerous since object might be something other than the target class type. In C#, downcasting is much safer. In fact, an illegal cast of an object throws an exception of type InvalidCastException. We verify that sender is a MenuItem object to ensure that an exception will not be thrown here.
dThe Index parameter is used to set the currently selected mode as well as an index into the modeMenuArray variable for determining the new value for the SizeMode property.
eWindows Forms controls support the Invalidate method. This method invalidates the contents of the control so that the system will redraw, or paint, any changes onto the screen. In this case, we want the control to redraw the image with our new
SizeMode setting.
Look carefully at what we have done here. This code is based solely on the index of the menu within its parent. We can add new menu items to our View menu or even use an alternate menu with a similar list of items. As long as we keep our
Array up to date, this method will reset the SizeMode property appropriately.
TRY IT! Compile your code and verify that the PictureBox.SizeMode property is altered when you select a different submenu item. The PictureBox.SizeMode property contains more than just the two settings we use here. Add a menu item to the Image menu called menuCenter with text Center Image to handle the CenterImage value for this property. You will need to add a new MenuItem to the menuImage menu and modify the modeMenuArray definition to include this new value.
We now have a Click handler that will modify the way an image is displayed based on the user’s selection. Unfortunately, our interface does not indicate the current display mode in the Image submenu. We will address this problem in the next section by adding a check mark to the current value.
3.4.2HANDLING POPUP EVENTS
Users appreciate feedback on the current settings for an application. Our current interface does not yet do this. The user has to understand the possible displays modes in order to know what is currently selected and to choose a different setting. A nicer interface would somehow highlight the current selection in the menuImage submenu. This would immediately indicate what mode is currently displayed, and help our user make a more informed selection.
If you look at the MenuItem class, there is a Checked property that, when true, will display a check mark next to the menu. This property could be set whenever the
POPUP EVENTS AND SHARED HANDLERS |
93 |