- •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 code also sets the InitialDirectory property to the current directory using the Environment class. This ensures that the initial directory in the dialog is always the current directory for our application. While this may not seem so relevant right now, it will become important when we implement Click handlers for our Save and Save As menus. We will look at the Environment class in more detail later in the chapter.
The menuAdd_Click method is similar to our original Load menu handler, but also very different. In particular, this method leaves unresolved the issue of what to display in the form, and the exception handling has been removed. We will handle these issues subsequently. For now, let’s move on to the Remove menu handler.
6.2.2REMOVING IMAGES FROM AN ALBUM
The event handler for the Remove menu uses the CurrentPosition property to locate the current photo and delete it from the album.
|
|
IMPLEMENT REMOVE HANDLER |
|
|
|
|
|
|
Action |
|
Result |
|
|
|
|
1 |
Add a Click handler for |
|
protected void menuRemove_Click |
|
the Remove menu. |
|
(object sender, System.EventArgs e) |
|
|
|
{ |
|
|
|
|
2 |
Implement this handler to |
|
if (_album.Count > 0) |
|
remove the current photo |
|
{ |
|
from the album. |
|
_album.RemoveAt(_album.CurrentPosition); |
|
|
_bAlbumChanged = true; |
|
|
|
|
|
|
|
|
} |
|
|
|
this.Invalidate(); |
|
|
|
} |
|
|
|
|
The menuRemove_Click handler uses the RemoveAt method from our PhotoAlbum class to remove the current photo. The issue of adjusting the current position in case we remove the last photo from the album is left to the PhotoAlbum class to handle. If you recall, the RemoveAt method we implemented in chapter 5 ensures that the current index remains valid after it is called through an override of the moveComplete method, so the current position is properly updated here.
Once again we have ignored the display issues. This is because our menu handlers will no longer interact with the Form window directly. Instead we will override the protected OnPaint method for this purpose, which is our next topic.
6.3PAINT EVENTS
Now that we can load multiple images into our album, we need a way to make them appear in the window. In previous chapters, we have simply assigned the selected photo to the Image property of our PictureBox control and relied on the .NET Framework to deal with the rest. The framework will still do most of the work, but now we need to identify which image from our album should be drawn.
PAINT EVENTS |
169 |
As in previous Microsoft development environments, such drawing is called painting in .NET. You may have noticed in chapter 3 that the Control class provides a Paint event for custom painting of a control. The event name is one piece of the support provided for each event in the .NET Framework. While we have seen these pieces in our previous use of events, this is a good place to list them more formally. The following support is required in order to define and support an event.
•A class that defines the event data. This is either the System.EventArgs class or a class derived from System.EventArgs. The event data for the Paint event is defined by the PaintEventArgs class. We will discuss the contents of the PaintEventArgs class in chapter 7.
•A delegate for the event. This delegate is used by Visual Studio .NET to add the event handler in the InitializeComponent method. By convention, the name of this delegate is the event name followed by the string “EventHandler.” The Paint event is supported by the PaintEventHandler delegate. The creation of delegates is discussed in chapter 9.
•A class that raises the event. This class must define the event and provide a method to raise the event. By convention the method to raise the event is the string “On” followed by the event name. The protected OnPaint method raises the Paint event.
For painting of controls, the Control class defines the Paint event. Within the definition of this class, the event is defined using the event keyword in C#.
public event PaintEventHandler Paint;
6.3.1DRAWING THE CURRENT PHOTOGRAPH
Returning to our code, we need a way to draw the appropriate photograph in our album. We could handle the Paint event directly in our Form or PictureBox control for this purpose. Instead, since the MainForm class derives from the Form class, we can override the method that raises the event directly. This technique is preferred where possible to avoid the extra overhead of creating and invoking an event handler. In this case, we will override the protected OnPaint method to handle the Paint event.
170 |
CHAPTER 6 COMMON FILE DIALOGS |
Set the version number of the MyPhotos application to 6.4.
OVERRIDE THE ONPAINT METHOD
|
Action |
Result |
|
|
|
1 |
In the MainForm.cs file override the |
protected override void OnPaint( |
|
OnPaint method. |
PaintEventArgs e) |
|
|
{ |
|
|
|
2 |
Only paint an image if the album is |
if (_album.Count > 0) |
|
not empty. |
{ |
|
Note: The three comments here |
// Paint the current image |
|
// Update the status bar |
|
|
are implemented in the subsequent |
} |
|
steps. In all cases, the status bar is |
else |
|
{ |
|
|
invalidated. |
|
|
// Indicate the album is empty |
|
|
|
} |
|
|
statusBar1.Invalidate(); |
|
|
|
3 |
Call OnPaint in the base class. |
base.OnPaint(e); |
|
|
} |
|
|
Note: This call is required to ensure that any |
|
|
Paint event handlers registered with the Form |
|
|
are called. As mentioned in chapter 5, the base |
|
|
keyword refers to the base class of the current |
|
|
object. |
|
|
|
4 |
Paint the current image by setting |
// Paint the current image |
|
the Image property of the pbxPhoto |
Photograph photo = _album.CurrentPhoto; |
|
control. |
pbxPhoto.Image = photo.Image; |
|
|
|
|
|
|
5 |
Update the status bar to hold the |
// Update the status bar. |
|
appropriate information about the |
sbpnlFileName.Text = photo.FileName; |
|
image. |
sbpnlImageSize.Text = String.Format |
|
("{0:#} x {1:#}", |
|
|
|
|
|
Note: The code here is similar to |
photo.Image.Width, |
|
what we used in our |
photo.Image.Height |
|
); |
|
|
menuLoad_Click event handler in |
|
|
statusBar1.ShowPanels = true; |
|
|
chapter 4. |
|
|
|
|
6 |
When no images are present, clear |
// Indicate the album is empty |
|
the screen and display an |
pbxPhoto.Image = null; |
|
appropriate status bar message. |
statusBar1.Text = "No Photos in Album"; |
|
|
|
|
|
statusBar1.ShowPanels = false; |
|
|
|
6.3.2DISPLAYING THE CURRENT POSITION
Before we see our changes in action, it would be nice to have some indication of our current position within the album and the total album size in the window. We can do this by adding a new StatusBarPanel to hold this information, as detailed by the following steps.
PAINT EVENTS |
171 |
ADD A NEW STATUS BAR PANEL
|
|
Action |
Result |
||
|
|
|
|
|
|
1 |
In the MainForm.cs Design window, |
The StatusBarPanel Collection Editor dialog |
|||
|
display the StatusBarPanel Collection |
appears as was shown in chapter 4. |
|||
|
Editor for the statusBar1 control. |
|
|||
|
How-to |
|
|
|
|
|
a. Display the properties for this control. |
|
|||
|
b. Click on the Panels property item. |
|
|||
|
c. Click the … button. |
|
|||
|
|
|
|
|
|
2 |
Add a new StatusBarPanel in this |
The new panel is added to the Panels collection. |
|||
|
dialog just before the existing |
The source code in the InitializeComponent |
|||
|
sbpnlImagePercent panel. |
method is updated to define the new panel and |
|||
|
How-to |
|
|
add it to the status bar. |
|
|
|
|
|
||
|
a. Click the Add button. |
|
|||
|
b. Click the up arrow in the center of |
|
|||
|
the dialog to move the panel just |
|
|||
|
beforethe image percent panel. |
|
|||
|
c. Assign the proper settings as shown. |
|
|||
|
d. Click OK to add the panel. |
|
|||
|
|
Settings |
|
||
|
|
|
|
|
|
|
|
Property |
Value |
|
|
|
|
(Name) |
sbpnlFileIndex |
|
|
|
|
AutoSize |
Contents |
|
|
|
|
ToolTipText |
Image Index |
|
|
|
|
|
|
|
|
3 |
In the OnPaint method, set the text for |
sbpnlFileIndex.Text = String.Format |
|||
|
this panel to contain the image index |
("{0:#}/{1:#}", |
|||
|
and album size. |
|
|
_album.CurrentPosition+1, |
|
|
|
|
_album.Count); |
||
|
|
|
|
|
|
|
|
|
|
|
|
The preceding tables have made a number of changes to the OnPaint method. The following code pulls together all of the pieces presented in the preceding tables. We will not discuss these changes in additional detail.
protected override void OnPaint(PaintEventArgs e)
{
if (_album.Count > 0)
{
// Paint the current image
Photograph photo = _album.CurrentPhoto; pbxPhoto.Image = photo.Image;
// Update the status bar. sbpnlFileName.Text = photo.FileName;
sbpnlFileIndex.Text = String.Format("{0}/{1}", _album.CurrentPosition+1, _album.Count);
sbpnlImageSize.Text = String.Format("{0} x {1}", photo.Image.Width, photo.Image.Height);
172 |
CHAPTER 6 COMMON FILE DIALOGS |