- •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
Set the version number of the MyPhotoAlbum library to 7.2.
IMPLEMENT A SCALETOFIT METHOD IN THE PHOTOGRAPH CLASS
|
Action |
Result |
|
|
|
1 |
In the Photograph.cs file, add the |
public Rectangle ScaleToFit |
|
ScaleToFit method. |
(Rectangle targetArea) |
|
|
{ |
|
|
|
2 |
Define a Rectangle to hold the |
Rectangle result |
|
calculated result. |
= new Rectangle(targetArea.Location, |
|
|
targetArea.Size); |
|
|
|
3 |
Determine whether the photograph |
// Determine best fit: width or height |
|
will fit best horizontally or vertically. |
if (result.Height * Image.Width |
|
|
> result.Width * Image.Height) |
|
|
{ |
|
|
|
4 |
If horizontally, determine the |
// Final width should match target, |
|
resulting height and center the |
// determine and center height |
|
rectangle in the available space. |
result.Height = result.Width |
|
* Image.Height / Image.Width; |
|
|
|
|
|
|
result.Y += (targetArea.Height |
|
|
- result.Height) / 2; |
|
|
} |
|
|
|
5 |
If vertically, determine the resulting |
else |
|
width and center the rectangle in |
{ |
|
the available space. |
// Final height should match target, |
|
// determine and center width |
|
|
|
|
|
|
result.Width = result.Height |
|
|
* Image.Width / Image.Height; |
|
|
result.X += (targetArea.Width |
|
|
- result.Width) / 2; |
|
|
} |
|
|
|
6 |
Return the calculated result. |
return result; |
|
|
} |
|
|
|
Since this algorithm is a bit off-topic from Windows Forms development, we will not discuss it in much detail. This gives us a mechanism for scaling our image to the proper display size, and accounts for both horizontal and vertical images. The method returns a Rectangle object containing both a location and a size for the new image. That is, this method does not just provide the final size for our displayed image; it also provides the location where it should appear within the target rectangle.
With this in hand, let’s turn back to our MyPhotos application. To implement our Scale to Fit menu, we need to add the menu item itself, the menu-handling logic, and the appropriate drawing code. We will begin with the menu option.
IMAGE DRAWING |
207 |
|
|
|
ADD SCALETOFIT MENU ITEM |
||
|
|
|
|
|
|
|
|
Action |
Result |
||
|
|
|
|
|
|
7 |
In the MainForm.cs [Design] window, |
|
|||
|
add a Scale To Fit menu to the top of |
|
|||
|
the View menu.. |
|
|
|
|
|
|
Settings |
|
||
|
|
|
|
|
|
|
|
Property |
Value |
|
|
|
|
(Name) |
menuScale |
|
|
|
|
Text |
&Scale to Fit |
|
|
|
|
|
|
|
|
8 |
Add the menuImage_ChildClick |
The handler is registered with the Click event |
|||
|
method as the Click event handler for |
associated with the menu. |
|||
|
the menuScale menu item. |
|
|||
|
|
|
|
|
|
The code generated by these steps is similar to the menu code generated in chapter 3 and elsewhere. In particular, note that the Index property settings for these menus are adjusted in the InitializeComponent method to reflect the insertion of the new item at the first location.
menuScale.Index = 0;
menuStretch.Index = 1;
menuActual.Index = 2;
Since the DisplayMode enumeration must match our menu, we need to update the values appropriately.
UPDATE DISPLAYMODE ENUMERATION
|
Action |
Result |
|
|
|
9 |
Locate the DisplayMode definition in |
private enum DisplayMode |
|
the MainForm.cs source file. |
{ |
|
|
|
10 |
Add a ScaleToFit value and adjust |
ScaleToFit = 0, |
|
the settings to match the Image |
StretchToFit = 1, |
|
submenu. |
ActualSize = 2 |
|
} |
|
|
|
|
|
|
|
11 |
Set the default value for the |
private DisplayMode _selectedMode |
|
_selectedMode field to the new |
= DisplayMode.ScaleToFit; |
|
setting. |
|
|
|
|
We also need to check each place in the code where this enumerator is used. If you do a search, you will discover the _selectedMode field in menuImage_Popup, menuImage_ChildClick, and OnPaint. The popup event is not affected by this change, but the click handler requires a change to its switch block.
208 |
CHAPTER 7 DRAWING AND SCROLLING |
UPDATE MENUIMAGE_CHILDCLICK EVENT HANDLER
|
Action |
Result |
|
|
|
12 |
Locate the |
protected void menuImage_ChildClick |
|
menuImage_ChildClick method in |
(object sender, System.EventArgs e) |
|
the MainForm.cs source file. |
{ |
|
. . . |
|
|
|
|
|
|
|
13 |
Add the new display mode to the |
switch (_selectedMode) |
|
switch statement, and make it the |
{ |
|
default. |
default: |
|
case DisplayMode.ScaleToFit: |
|
|
|
|
|
|
// Scale image to fit display area |
|
|
this.Invalidate(); |
|
|
break; |
|
|
case DisplayMode.StretchToFit: |
|
|
. . . |
|
|
} |
|
|
. . . |
|
|
} |
|
|
|
The final change required to properly scale our image is in the OnPaint method. Here we simply draw the image into the Rectangle determined by our Photograph.ScaleToFit method.
|
|
UPDATE ONPAINT METHOD |
|
|
|
|
Action |
Result |
|
|
|
14 |
Locate the OnPaint |
protected override void OnPaint(PaintEventArgs e) |
|
method in the |
{ |
|
MainForm.cs source file. |
. . . |
|
|
|
|
|
|
15 |
Add the new display mode |
switch (_selectedMode) |
|
to the switch statement, |
{ |
|
and make it the default. |
default: |
|
case DisplayMode.ScaleToFit: |
|
|
|
|
|
|
// Preserve aspect ratio of image |
|
|
g.DrawImage(photo.Image, |
|
|
photo.ScaleToFit(DisplayRectangle)); |
|
|
break; |
|
|
case DisplayMode.StretchToFit: |
|
|
. . . |
|
|
} |
|
|
. . . |
|
|
} |
|
|
|
There you have it. The Scale to Fit display mode is very similar to the Stretch to Fit display mode. Both fit the image into the display area, and both draw the image into a rectangle. The difference is the rectangle into which they draw. Compile your application to verify that the image scales properly. It may be a bit hard to determine if this is working properly since a window resize does not cause the image to be redrawn. Let’s address this problem next.
IMAGE DRAWING |
209 |
7.2.5REPAINTING WHEN THE FORM IS RESIZED
Now that we are drawing directly on the form, we need to redraw our image whenever the form is resized. The PictureBox control used in prior chapters handled this issue automatically for us.
There is in fact a Resize event associated with controls. This event occurs when
a control, including a Form object, is resized. Handling this event would allow us to invalidate the window whenever the display mode is ScaleToFit or StretchToFit. Since our MainForm class is derived from Form, we could even go directly to the protected OnResize method that raises this event. This would force our OnPaint method to be called and the window would update appropriately. A fine idea, but there is another way.
.NET Table 7.4 ControlStyles enumeration
The ControlStyles enumeration specifies a set of values related to the interaction of a control with the Windows desktop. These styles define how low-level Windows messages are processed by the control when a user interacts with it in various ways. This enumeration is part of the System.Windows.Forms namespace.
The values in this enumeration can be combined using the bitwise “or” operator. The protected GetStyle and SetStyle methods in the Control class can be used to modify these settings for a control.
|
DoubleBuffer |
Whether to perform drawing in a buffer and |
|
|
|
output the result to the screen after it |
|
|
|
completes. This prevents flicker caused by |
|
|
|
redrawing the control. |
|
|
FixedHeight |
Whether the control has a fixed height. |
|
|
FixedWidth |
Whether the control has a fixed width. |
|
|
ResizeRedraw |
Whether the control is completely redrawn |
|
|
|
when it is resized. |
|
|
Selectable |
Whether the control can get the focus. |
|
Enumeration |
StandardClick |
Whether OnClick is called when the control is |
|
Values |
|||
|
single-clicked. Note that the control may still call |
||
|
|
||
|
|
OnClick directly. |
|
|
StandardDoubleClick |
Whether OnDoubleClick is called when the |
|
|
|
control is double clicked. Note that the control |
|
|
|
may still call OnDoubleClick directly. |
|
|
UserMouse |
Whether the control does its own mouse |
|
|
|
processing. If so, then mouse messages are not |
|
|
|
passed to the control.a |
|
|
UserPaint |
Whether the control paints itself. If so, then paint |
|
|
|
messages are not passed to the control. |
|
|
|
|
a. Actually, the messages here are not passed to the underlying NativeWindow object, but you can think of it as the control itself. For UserMouse, this affects the WM_MOUSEDOWN, WM_MOUSEMOVE, and WM_MOUSEUP messages. For UserPaint, this affects the WM_PAINT and WM_ERASEBKGND messages.
210 |
CHAPTER 7 DRAWING AND SCROLLING |