- •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
The .NET Framework defines a ControlStyles enumeration, summarized in
.NET Table 7.4, for customizing the behavior of a control. The values defined by this enumeration indicate how the control appears or responds in various situations related to desktop interaction with a user, and are useful for customizing the behavior of a Form or other custom control class.
The Control class provides a SetStyle method to set these styles, and a GetStyle method to retrieve the current setting for these styles. These methods are protected, so you must inherit from an existing control in order to modify these styles.
For our purposes, you may have noticed the ResizeRedraw style, which we can use to force our application to redraw itself every time the user resizes the window.
|
FORCE THE FORM TO REDRAW WHEN RESIZED |
|
|
|
|
|
Action |
Result |
|
|
|
1 |
Locate the |
protected void menuImage_ChildClick |
|
menuImage_ChildClick |
(object sender, System.EventArgs e) |
|
{ |
|
|
method in the |
|
|
. . . |
|
|
MainForm.cs source file. |
|
|
|
|
|
|
|
2 |
Modify the logic when the |
switch (_selectedMode) |
|
display mode is |
{ |
|
ScaleToFit or |
default: |
|
case DisplayMode.ScaleToFit: |
|
|
StretchToFit to force a |
|
|
case DisplayMode.StretchToFit: |
|
|
redraw whenever the form |
SetStyle(ControlStyles.ResizeRedraw, |
|
resizes. |
true); |
|
|
Invalidate(); |
|
|
break; |
|
|
. . . |
|
|
} |
|
|
. . . |
|
|
} |
|
|
Note: Since the logic is the same for these two modes, |
|
|
we have merged these two case labels into a single |
|
|
block. C# allows a case label to fall through to the next |
|
|
label only if it has no code associated with it. |
|
|
|
We will make one other change here before testing our program. When the program begins, the ResizeRedraw style is not set to true. Only after the user makes a selection will this style be set appropriately. A simple solution would be to set the ResizeRedraw style in the constructor for our form. This works, but does not account for any future changes to the menuImage_ChildClick method. Since such changes will occur in the next section, a more robust solution is to simulate an Image menu selection directly from the constructor.
Simulating a call to an event handler during control initialization is a good way to ensure that future changes to the handler are dealt with during initialization. It also allows you to make such changes in only one place. We did this in the previous chapter for the New menu. Let’s do this here by continuing the previous steps.
IMAGE DRAWING |
211 |
SIMULATE AN IMAGE MENU CLICK IN MAINFORM CONSTRUCTOR
|
Action |
Result |
|
|
|
3 |
Locate the MainForm |
public MainForm() |
|
constructor in the |
{ |
|
MainForm.cs source |
. . . |
|
|
|
|
window. |
|
|
|
|
4 |
Add a call to |
menuImage_ChildClick(menuScale, |
|
menuImage_ChildClick |
EventArgs.Empty); |
|
} |
|
|
in this constructor. |
|
|
|
|
|
How-to |
Note: This call must occur after the InitializeCompo- |
|
nent method has been called to ensure that the menu |
|
|
a. Use the menuScale |
|
|
objects have been initialized. |
|
|
menu as the sender |
|
|
|
|
|
parameter. |
|
|
b. Use EventArgs.Empty |
|
|
for the event parameter. |
|
|
|
|
Now you can compile and run the application to see the amazing ResizeRedraw style in action. This code uses the static EventArgs.Empty property we saw in chapter 6 to provide a valid, albeit empty, event argument to the handler.
TRY IT! If you are tired of reading, modify your code to use the Resize event instead of the ResizeRedraw control style. This change reduces the processing required when an Image submenu item is selected, at the expense of additional processing whenever the window is resized. Do this by overriding the OnResize method for the form, and use the _selectedMode field to invalidate the window as required.
Another change you can make is to modify the form to do double buffering. This removes the flicker that currently occurs when resizing the image. To do this, use the following code in the menuImage_ChildClick method:
SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.DoubleBuffer, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
This completes the drawing of an image within the window. While we have lost our border, we are now able to draw the image in our window using either the Stretch to Fit or Scale to Fit display options. Our next task is to handle the Actual Size menu to draw the full-sized image in the window. This requires the use of scroll bars and will lead us into a discussion of the Panel class.
7.3AUTOMATED SCROLLING
The implementation of the Actual Size menu option allows us to look at the ScrollableControl class in more detail. As we have seen, the actual image is often larger than the form’s client area. In chapter 3, the PictureBox control did not support
212 |
CHAPTER 7 DRAWING AND SCROLLING |
scrolling and we could only view the rest of the image by resizing the form. Here, we will use scroll bars via the ScrollableContainer class members to provide a more appropriate solution.
The result of our labors is shown in figure 7.4. As you can see, part of the image is shown, and scroll bars at the right and bottom of the image can be used to scroll to the remainder of the image. These scroll bars will appear and disappear automatically as needed. You may wonder where our status bar has gone. This is an unfortunate side effect drawing directly on our form, and is the reason a section 7.4 exists in this chapter. More on this later.
Figure 7.4
The scroll bars for the form appear automatically when the display area is larger than the client area.
7.3.1PROPERTIES FOR SCROLLING
We already have the Actual Size menu available, but we need to add the appropriate processing when this menu is clicked and in the OnPaint method. Before we write any code, let’s consider which properties we need from the ScrollableControl class.
ScrollableControl properties for scrolling our image
Property |
Purpose |
|
|
AutoScroll |
Whether scrolling is enabled. We will set this to true for the Actual Size |
|
mode, and false for other display modes. |
AutoScrollMinSize |
The minimum size for the scrollable window. This is the display size, and not |
|
the actual client size seen by the user. We will set this to the size of the |
|
current image to ensure that the scroll bars are sized appropriately for this |
|
image. |
AutoScrollPosition |
The window position, in pixels, at the upper left corner of the window. This |
|
property is adjusted automatically as the window scrolls. |
|
|
7.3.2IMPLEMENTING AUTOMATED SCROLLING
Now that we have reviewed some of the properties used for automated scrolling, we can tackle the code required for the ActualSize display mode. We will start with the menu click, and handle the painting of the image in a moment.
AUTOMATED SCROLLING |
213 |
When the user clicks the ActualSize display mode, we need to adjust not just the Actual Size display mode, but also our Scale to Fit and Stretch to Fit menus to ensure that scrolling is disabled when these modes are set. The following steps detail the changes required.
Set the version number of the MyPhotos application to 7.3.
MODIFY MENUIMAGE_CHILDCLICK FOR ACTUALSIZE DISPLAY MODE
|
Action |
Result |
|
|
|
1 |
Locate the menuImage_ChildClick |
protected void menuImage_ChildClick |
|
method in the MainForm.cs source |
(object sender, System.EventArgs e) |
|
window. |
{ |
|
. . . |
|
|
|
|
|
|
|
2 |
Turn scrolling off for the ScaleToFit |
switch (_selectedMode) |
|
and StretchToFit display modes. |
{ |
|
|
default: |
|
|
case DisplayMode.ScaleToFit: |
|
|
case DisplayMode.StretchToFit: |
|
|
// Display entire image in window |
|
|
AutoScroll = false; |
|
|
SetStyle(ControlStyles.ResizeRedraw, |
|
|
true); |
|
|
. . . |
|
|
|
3 |
Turn scrolling on for the ActualSize |
case DisplayMode.ActualSize: |
|
display mode. |
// Display image at actual size |
|
|
AutoScroll = true; |
|
How-to |
SetStyle(ControlStyles.ResizeRedraw, |
|
a. Set AutoScroll to true. |
false); |
|
Invalidate(); |
|
|
b. Turn off the ResizeRedraw style |
break; |
|
} |
|
|
for the form. |
|
|
. . . |
|
|
|
|
|
|
} |
|
|
|
Note here that we did not set AutoScrollMinSize to the size of the current image. Since different images may have different sizes, we will need to adjust this setting whenever the current image changes. One way to do this would be to modify this setting in all the places where the current image changes. This would include the Next, Previous, and Remove menu handlers, and possibly other locations in the future as well. That’s a lot to keep track off. Instead, we will set this property when the image is painted so that it is updated by default whenever the image changes.
For the Paint operation itself, another version of the Graphics.DrawImage method is used to account for drawing the image into a space larger than the client area. The DrawImage method has a number of overloads to handle various types of drawing. See the documentation for the complete list.
214 |
CHAPTER 7 DRAWING AND SCROLLING |