
- •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

MODIFY ONPAINT METHOD FOR ACTUALSIZE DISPLAY MODE
|
Action |
Result |
|
|
|
4 |
Locate the OnPaint method |
protected override void OnPaint(PaintEventArgs e) |
|
in the MainForm.cs source |
{ |
|
window. |
. . . |
|
|
|
|
|
|
5 |
When the display mode is |
case DisplayMode.ActualSize: |
|
ActualSize, draw the |
// Draw appropriate portion of image |
|
image into the display area. |
g.DrawImage(photo.Image, |
|
AutoScrollPosition.X, |
|
|
|
|
|
|
AutoScrollPosition.Y, |
|
|
photo.Image.Width, |
|
|
photo.Image.Height); |
|
|
|
6 |
Also set the |
AutoScrollMinSize = photo.Image.Size; |
|
AutoScrollMinSize |
break; |
|
. . . |
|
|
property as appropriate. |
|
|
} |
|
|
|
|
|
|
|
That’s it! Your application will now handle all three display modes. Note how the AutoScrollPosition property is used for the location to appear in the upper left corner of the client area. As the window scrolls, this value is updated automatically so we can use it future Paint operations.
Crank it up and display your favorite set of images stretched to fit, scaled to fit, and at the actual size. Make sure you try some images of alternate sizes to ensure that the scroll bars adjust appropriately as you move through the album. Also note how the scroll bars disappear when the window is expanded to be larger than the image.
Too bad about our status bar. It really should not be part of the scrolled area here. The problem is that we are drawing and scrolling the form itself, and both the image and the status bar are part of the form. As a result, as goes the image, so goes the status bar. To fix this, we need to isolate the image portion of the form and have our image appear only in this area. The PictureBox control isolated the image without the ability to scroll. The Panel class will provide both isolation and scrolling.
7.4PANELS
If you have prior experience with MFC, then you must know how frustrating the MFC group box control can be. A fine control, I would submit, except when you have to adjust its position, or worse, add controls inside of it. The problem, for those not familiar with this construct, is that it is just a box, with no relationship to the inside of the box. If you move the box, you have to adjust the contents separately, and vice versa. Very frustrating.
In the .NET Framework, controls can act as containers for other controls. When you move the container, the controls inside move with it. Two such containers in the
System.Windows.Forms namespace are the GroupBox and Panel classes. When you move a .NET container, the contents move with it. The position of the inner controls are defined in relationship to the container, and the Anchor and Dock properties are used to set their resize behavior within the container just like within a form.
PANELS |
215 |

Our focus in this section will be the Panel class. This class can contain and position controls just like the Form class, and supports automated scrolling since it inherits from the ScrollableControl class.2 We will not position controls within a panel in this chapter, but we will use this class to fix some of the problems we have seen when drawing directly on the form. We will draw our photo directly in a Panel, and solve the following problems we noticed when drawing directly on the form:
•Our image was off-center vertically for the Scale to Fit display option. The DisplayRectangle property included the vertical space occupied by the
scroll bar, which threw our calculations off. Here, we will use the panel’s playRectangle property, so that the image will be centered exactly inside the panel.
•The 3-D border we used for the PictureBox control was gone. We could have attempted to draw a border inside the form using the ControlPaint.DrawBorder3D method, but a Panel provides a much easier solution. The Panel class provides a BorderStyle property much like the corresponding PictureBox property, so the .NET framework will draw the border for us.
•The status bar was part of the scrollable area. Since the Form object managed the scrolling, the StatusBar control on the form was caught up in the scrolling logic. In this section, the scrolling will be managed by the Panel class independent of the form and status bar. As a result, our status bar will return to and remain at its natural position at the base of the form.
Before we get into the required changes, figure 7.5 shows how our three display modes will appear by the end of this section. As you can see, the application looks much more polished here than when we drew directly on the form. Note especially the excellent centering, the fine border, and the well-behaved scroll bars.
Figure 7.5 This shows an image drawn inside a panel with the Scale to Fit, Stretch to Fit, and Actual Size display modes.
2 For the curious, the GroupBox control inherits from the Control class and does not support scrolling.
216 |
CHAPTER 7 DRAWING AND SCROLLING |

As you will see, the code to draw the image inside a panel is very similar to drawing the image directly on the form. We will need to add a new panel, update some of our menu handlers and the drawing of the status bar, and finally draw the image into the panel.
7.4.1ADDING A PANEL
Adding a Panel object in Visual Studio is much like adding any other control. You open the Toolbox and drag a Panel onto the form. In the source code, the panel is added using the Control property of the parent form. We will look at both of these, beginning with the use of Visual Studio.
Set the version number of the MyPhotos application to 7.4.
ADD A PANEL TO THE FORM
|
|
Action |
Result |
||
|
|
|
|
|
|
1 |
In the MainForm.cs [Design] window, drag a |
A Panel control is added to the window. |
|||
|
Panel control from the Toolbox onto the form. |
|
|||
|
|
|
|
|
|
2 |
Set the panel’s properties as shown. |
|
|||
|
|
Settings |
|
||
|
|
|
|
|
|
|
|
Property |
Value |
|
|
|
|
(Name) |
pnlPhoto |
|
|
|
|
BorderStyle |
Fixed3D |
|
|
|
|
Dock |
Fill |
|
|
|
|
|
|
|
|
Take a look at the MainForm.cs source file to see how the panel is created. As you can see, this code looks very similar to the code for other controls from prior chapters. A private instance is created in the MainForm class, initialized in the InitializeComponent method, and added to the form using the Form.Controls property.
private System.Windows.Forms.Panel pnlPhoto;
. . .
private void InitializeComponent()
{
. . .
this.pnlPhoto = new System.Windows.Forms.Panel ();
. . .
//
// pnlPhoto
//
this.pnlPhoto.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; this.pnlPhoto.Dock = System.Windows.Forms.DockStyle.Fill; this.pnlPhoto.Name = "pnlPhoto";
this.pnlPhoto.Size = new System.Drawing.Size(292, 233); this.pnlPhoto.TabIndex = 3;
. . .
this.Controls.AddRange(new System.Windows.Forms.Control[] { this.pnlPhoto, this.statusBar1});
PANELS |
217 |

The Panel class depends largely on its base classes for exported functionality, with the BorderStyle property just about the only new member added by the class. An overview of the Panel class appears in .NET Table 7.5.
.NET Table 7.5 Panel class
The Panel class represents a scrollable control that acts as a container for other controls. This class is often used to define a region of controls within a Form. This class is part of the System.Windows.Forms namespace and inherits from the ScrollableControl class. See .NET Table 7.1 on page 196 for a list of members inherited from the ScrollableControl class.
Public
Properties
BorderStyle |
Gets or sets the type of border to display around the |
|
control. |
DisplayRectangle |
Gets the display area for the control. When scrolling is |
(inherited from |
enabled, this property represents the entire scrollable area |
Control) |
for the panel. The ClientRectangle property represents |
|
the visible portion of the control. |
Enabled |
Gets or sets whether the panel is enabled. Controls within |
(inherited from |
the panel are disabled whenever the panel itself is disabled. |
Control) |
|
Visible (inherited |
Gets or sets whether the panel is visible. Controls within |
from Control) |
the panel are invisible if the panel itself is invisible. |
|
|
7.4.2UPDATING THE MENU HANDLERS
With our panel on the form, we need to update the code for drawing our image to use the new panel rather than interacting with the form itself. We will begin with the menu handlers for the Image submenu.
The menuImage_Popup method simply sets the Enabled and Checked menu properties as required for the current display mode. This behavior does not change, so no modifications are required. The menuImage_ChildClick method sets scrolling properties for the form. Since our scrolling will be managed from the Panel object now, we need to use the corresponding Panel members rather than those in the Form itself.
UPDATE THE MENUIMAGE_CHILDCLICK METHOD TO USE THE NEW PANEL
|
Action |
Result |
|
|
|
1 |
Locate the |
protected void menuImage_ChildClick |
|
menuImage_ChildClick method in |
(object sender, System.EventArgs e) |
|
the MainForm.cs source window. |
{ |
|
. . . |
|
|
|
|
|
|
|
2 |
Modify the code for the |
case DisplayMode.ScaleToFit: |
|
ScaleToFit and StretchToFit |
case DisplayMode.StretchToFit: |
|
display mode to set drawing-related |
SetStyle(ControlStyles.ResizeRedraw, |
|
true); |
|
|
properties on the Panel rather than |
|
|
pnlPhoto.AutoScroll = false; |
|
|
the parent Form. |
pnlPhoto.Invalidate(); |
|
|
break; |
|
|
|
218 |
CHAPTER 7 DRAWING AND SCROLLING |