
- •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
A number of classes are available in the System.Drawing namespace for drawing status bar panels, menu items, and other objects. An overview of this namespace is provided in .NET Table 4.5. Rather than provide detailed coverage of this namespace in any one chapter of the book, we will visit members of this namespace as required by our application. In particular, we will use this namespace again in chapter 7 when drawing on Form and Panel controls, and also in chapter 10 when discussing owner-drawn list boxes.
4.4.2DRAWING A PANEL
So let’s draw the panel in our application. If you recall, we want this panel to show what percentage of the image is shown in the PictureBox control. To do this, we need to handle the DrawItem event. We will build this code step by step. The complete code for the handler is shown following the table.
Set the version number of the application to 4.4.
|
|
ADD DRAWITEM HANDLER |
|
|
|
|
|
|
Action |
|
Result |
|
|
|
|
1 |
Handle the DrawItem event |
|
An event handler for the DrawItem event is added to the |
|
for the StatusBar control in |
|
control. |
|
the MainForm.cs [Design] |
|
protected void statusBar1_DrawItem |
|
window. |
|
|
|
|
(object sender, |
|
|
How-to |
|
StatusBarDrawItemEventArgs sbdevent) |
|
|
{ |
|
|
In the Properties window for |
|
|
|
|
|
|
|
the status bar, double-click |
|
|
|
the DrawItem entry. |
|
|
|
|
|
|
2 |
In this handler, check that the |
|
if (sbdevent.Panel == sbpnlImagePercent) |
|
panel to draw is the |
|
{ |
|
sbpnlImagePercent panel. |
|
// Calculate the percent of the image shown |
|
|
// Calculate the rectangle to fill |
|
|
|
|
|
|
Note: This if statement is |
|
// Draw the rectangle in the panel |
|
not strictly necessary. Still, |
|
// Draw the text on top of the rectangle |
|
|
} |
|
|
since the event relates to the |
|
|
|
|
} |
|
|
entire status bar and not just |
|
Note: The four comments here are the four steps that |
|
this panel, this provides |
|
|
|
|
must be performed to draw the panel. Each step is |
|
|
some robustness against |
|
|
|
|
performed in the subsequent four steps of this table. |
|
|
future changes. |
|
|
|
|
|
|
|
|
|
|
OWNER-DRAWN PANELS |
121 |

ADD DRAWITEM HANDLER (continued)
|
Action |
Result |
|
|
|
3 |
Calculate what percentage of |
// Calculate the percent of the image shown |
|
the image appears in the |
int percent = 100; |
|
window. |
if (pbxPhoto.SizeMode |
|
!= PictureBoxSizeMode.StretchImage) |
|
|
|
|
|
How-to |
{ |
|
Rectangle dr = pbxPhoto.ClientRectangle; |
|
|
a. If the SizeMode setting for |
|
|
int imgWidth = pbxPhoto.Image.Width; |
|
|
the image is StretchIm- |
int imgHeight = pbxPhoto.Image.Height; |
|
age, use 100% of the |
percent = 100 * Math.Min(dr.Width, imgWidth) |
|
panel. |
* Math.Min(dr.Height, imgHeight) |
|
/ (imgWidth * imgHeight); |
|
|
b. Otherwise, divide the |
|
|
} |
|
|
smaller of the display area |
|
|
and the image size by the |
|
|
total image area. |
|
|
c. For simplicity, use integer |
|
|
percent values. |
|
|
|
|
4 |
Calculate the rectangular |
// Calculate the rectangle to fill |
|
region to fill. |
Rectangle fillRect = sbdevent.Bounds; |
|
|
fillRect.Width = sbdevent.Bounds.Width |
|
How-to |
* percent / 100; |
|
Use the event’s Bounds |
|
|
property and adjust its Width |
|
|
based on the calculated |
|
|
percent. |
|
|
|
|
5 |
Draw this rectangle in the |
// Draw the rectangle in the panel |
|
panel. |
sbdevent.Graphics.FillRectangle( |
|
|
Brushes.SlateGray, fillRect); |
|
How-to |
Note: We could also have used the ForeColor prop- |
|
a. Use the Graphics object |
|
|
erty of the event as the color here. This code illus- |
|
|
for the event. |
trates using the Brushes class, which provides access |
|
b. Paint the rectangle with the |
to a Brush object for all standard colors available in the |
|
FillRectangle method, |
framework. |
|
using a SlateGray brush. |
|
|
|
|
6 |
Draw the percentage value in |
// Draw the text on top of the rectangle |
|
the panel. |
sbdevent.Graphics.DrawString( |
|
|
percent.ToString() + "%", |
|
How-to |
sbdevent.Font, |
|
Use the DrawString |
Brushes.White, |
|
sbdevent.Bounds); |
|
|
method for the Graphics |
|
|
Note: White is a good color choice if used with the |
|
|
object. |
|
|
default desktop colors. It may not be a good choice if |
|
|
|
|
|
|
custom desktop colors are used. |
|
|
|
The complete code for this handler is shown as follows:
protected void statusBar1_DrawItem (object sender, StatusBarDrawItemEventArgs sbdevent)
{
if (sbdevent.Panel == sbpnlImagePercent)
122 |
CHAPTER 4 STATUS BARS |
{
// Calculate the percent of the image shown int percent = 100;
if (pbxPhoto.SizeMode != PictureBoxSizeMode.StretchImage)
{
Rectangle dr = pbxPhoto.ClientRectangle; int imgWidth = pbxPhoto.Image.Width;
int imgHeight = pbxPhoto.Image.Height; percent = 100 * Math.Min(dr.Width, imgWidth)
* Math.Min(dr.Height, imgHeight) / (imgWidth * imgHeight);
}
//Calculate the rectangle to fill Rectangle percentRect = sbdevent.Bounds;
percentRect.Width = sbdevent.Bounds.Width * percent / 100;
//Draw the rectangle in the panel sbdevent.Graphics.FillRectangle(Brushes.SlateGray, percentRect);
//Draw the text on top of the rectangle sbdevent.Graphics.DrawString(percent.ToString() + "%",
sbdevent.Font, Brushes.White, sbdevent.Bounds);
}
}
The Graphics class used in this handler provides a rich set of drawing capabilities, from circles, ellipses, and rectangles to polygons, pie shapes, and bezier curves. Here we use the FillRectangle method, which requires a Brush object to use when “painting” the rectangle. In chapter 7, we will make additional use of this class. See
.NET Table 4.6 for an overview of some of the more interesting members of this class. It should be noted that the statusBar1_DrawItem handler is invoked each time a panel must be redrawn. As a result, care should be taken in handlers such as this to avoid expensive calculations or other operations that might adversely affect the performance of the application. For example, if we had generated a custom Brush object while filling the rectangle here, such an operation would be performed each time the handler is invoked, potentially using an excessive amount of memory over the life of the application. Of course, our choice of the SlateGray color might not be the best choice either, as it might interfere with colors the user has selected for their desktop. A better option here might be to determine a color programmatically based on the user’s desktop settings, and generate a single Brush object the first time the
event handler is invoked that is reused for the life of the application.
You can compile and run this code so far if you like, but we do need to make one more change. When the PictureBox.SizeMode property is StretchImage, the complete image (100%) is always shown. When SizeMode is set to Normal, the amount of image shown varies as the size of the client area changes. As a result, when the user changes this setting, we need to make sure that our panel is redrawn by invalidating the contents of the status bar.
OWNER-DRAWN PANELS |
123 |

.NET Table 4.6 Graphics class
The Graphics class is a drawing object that encapsulates a drawing surface , or more specifically a graphical device interface (GDI+) drawing surface. This class is part of the System.Drawing namespace, and inherits from the System.MarshalByRefObject class. Drawing the outline of a shape typically requires a Pen object, while drawing a filled-in shape typically requires a Brush object.
This class contains a large number of members, but the list here should provide some idea of the supported functionality.
|
FromHdc |
Returns a Graphics instance from a given handle |
|
Public Static |
|
to a device context. |
|
|
|
||
Properties |
FromHwnd |
Returns a Graphics instance from a given |
|
|
|||
|
|
window handle. |
|
|
|
|
|
|
Clip |
Gets or sets as a Region object the portion of the |
|
|
|
graphics area available for visible drawing. |
|
|
DpiX |
Gets the horizontal resolution supported by the |
|
|
|
object. |
|
|
DpiY |
Gets the vertical resolution supported by the |
|
Public Properties |
|
object. |
|
PageUnit |
Gets or sets the GraphicsUnit value specifying |
||
|
|||
|
|
the unit of measure for page coordinates. |
|
|
SmoothingMode |
Gets or sets the SmoothingMode value indicating |
|
|
|
how shapes are rendered with this object. |
|
|
TextRenderingHint |
Gets or sets the TextRenderingHint value |
|
|
|
indicating how text is rendered with this object. |
|
|
|
|
|
|
Clear |
Fills the entire drawing surface with a specified |
|
|
|
color. |
|
|
DrawCurve |
Draws a curve specified as an array of points using |
|
|
|
a given Pen. |
|
|
DrawEllipse |
Draws the outline of an ellipse (which might be a |
|
|
|
circle) bounded by a given rectangle using a given |
|
|
|
Pen. |
|
|
DrawLine |
Draws a line using a given Pen. |
|
Public Methods |
DrawRectangle |
Draws the outline of a rectangle using a given Pen. |
|
|
|
||
|
FillClosedCurve |
Fills the interior of a closed curve specified as an |
|
|
|
array of points using a given Brush. |
|
|
FillEllipse |
Fills the interior of an ellipse (which might be a |
|
|
|
circle) bounded by a given rectangle using a given |
|
|
|
Brush. |
|
|
FillRectangle |
Fills the interior of a rectangle using a given |
|
|
|
Brush. |
|
|
MeasureString |
Returns the size a given string would occupy using |
|
|
|
a given Font. |
|
|
|
|
124 |
CHAPTER 4 STATUS BARS |