- •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
IMPLEMENT A CLICK HANDLER FOR THE SAVE MENU
|
Action |
Result |
|
|
|
1 |
Add a Click handler for the Save |
protected void menuSave_Click |
|
menu. |
(object sender, System.EventArgs e) |
|
|
{ |
|
|
|
2 |
If an album name does not exist, |
if (_album.FileName == null) |
|
use the Save As menu handler to |
{ |
|
prompt the user for an album |
// Need to select an album file |
|
menuSaveAs_Click(sender, e); |
|
|
name. |
|
|
} |
|
|
|
|
3 |
If an album name exists, then |
else |
|
simply save the file. |
{ |
|
|
// Save the album in the current file |
|
|
_album.Save(); |
|
|
|
4 |
Mark that the now-saved album |
_bAlbumChanged = false; |
|
has no changes. |
} |
|
|
} |
|
|
|
Note the neat trick we play between the Save and Save As Click handlers. When you save an album with no name, the Save handler calls the Save As handler to select a name, which then calls the Save handler to perform the actual save. The second time in the menuSave_Click method, a name will exist and the data will be saved.
Of course, whenever you interact with the file system, you should be concerned about possible exceptions. I intentionally ignored this issue here to whet your appetite for the next chapter. There, we will formally introduce the MessageBox class as a way to display simple dialogs to the user, most notably when an exception occurs.
Compile your code to verify that you can create an album and save it to disk. Open a saved album file in Notepad or some other text editor to see what it looks like. You should see something similar to the following:
66
C:\My Images\Samples\castle.jpg
C:\My Images\Samples\goose.jpg
C:\My Images\Samples\castle3.jpg
C:\My Images\Samples\gardens.jpg
Of course, saving the file is not very useful if you cannot also open a previously saved file. We will talk about this next.
6.7OPEN FILE DIALOGS
So far, we have provided our application with the ability to load multiple photographs to create a photo album, step between these photographs using the Next and Previous menus, and save the album onto disk. Our final task is to open a previously saved album and display the first photo in our window. As you probably realize, we need to implement the user interface portion by handling the Open menu in our MainForm class, and the data portion by implementing an Open method for our
PhotoAlbum class.
OPEN FILE DIALOGS |
189 |
As before, we will begin with our PhotoAlbum class.
6.7.1READING ALBUM DATA
The Open method will accept a file name and read the photo album stored in this file. It relies on the user interface layer in the caller to provide an actual file, and will throw an exception if an error occurs.
Set the version number of the MyPhotoAlbum library to 6.8.
IMPLEMENT AN OPEN METHOD IN THE PHOTOALBUM CLASS
|
Action |
Result |
|
|
|
1 |
In the PhotoAlbum.cs file, add an |
public void Open(string fileName) |
|
Open method to the class. |
{ |
|
|
|
2 |
Open the given file with read |
FileStream fs = new FileStream(fileName, |
|
access. |
FileMode.Open, |
|
|
FileAccess.Read); |
|
|
StreamReader sr = new StreamReader(fs); |
|
|
|
3 |
Read the version string from the |
int version; |
|
file and convert it to an integer. |
try |
|
How-to |
|
|
{ |
|
|
Use the Int32.Parse method. |
version = Int32.Parse(sr.ReadLine()); |
|
This will throw an exception if the |
} |
|
catch |
|
|
string is not actually an integer. |
|
|
{ |
|
|
|
version = 0; |
|
|
} |
|
|
|
4 |
Clear the existing album and |
try |
|
assign the new file name to the |
{ |
|
corresponding property. |
this.Clear(); |
|
this.FileName = fileName; |
|
|
|
|
|
|
|
5 |
Read in the list of photos. |
switch (version) |
|
Note: The C# switch statement |
{ |
|
case 66: |
|
|
used here allows for additional |
{ |
|
version numbers in the future. |
// Read in the list of image files |
|
|
string name; |
|
|
do |
|
|
{ |
|
|
name = sr.ReadLine(); |
|
|
if (name != null) |
|
|
{ |
|
|
// Add the name as a photograph |
|
|
Photograph p = new Photo- |
|
|
graph(name); |
|
|
this.Add(p); |
|
|
} |
|
|
} while (name != null); |
|
|
break; |
|
|
} |
|
|
|
190 |
CHAPTER 6 COMMON FILE DIALOGS |
IMPLEMENT AN OPEN METHOD IN THE PHOTOALBUM CLASS (continued)
|
Action |
Result |
|
|
|
6 |
If the version number is not |
default: |
|
recognized, throw an exception. |
// Unknown version or bad file. |
|
How-to |
throw (new IOException |
|
("Unrecognized album file format")); |
|
|
Use the C# throw keyword and |
} |
|
create an IOException object. |
|
|
|
|
7 |
Close the file objects regardless |
} |
|
of whether an exception occurs. |
finally |
|
Note: This disposes of any non- |
{ |
|
sr.Close(); |
|
|
memory resources for our files. |
fs.Close(); |
|
Make sure you close the files in |
} |
|
} |
|
|
the proper order. |
|
|
|
|
|
|
|
Note how our code reads the version number as a string and converts it to an integer using the Int32 class. The Parse method here throws an exception if a noninteger is provided. Since we really do not want the caller to see such an exception, we turn any exception thrown into a version number of zero to cause an unrecognized album exception to be thrown.
This code is our first use of the C# switch keyword. A switch block uses a case label just like C++ to identify a value to process, although C# switch blocks do not allow a fall through to the next case block unless the previous case has no code associated with it. Here, all our album files should be the current version 66 so only a single case label is required. We do not use the constant _CurrentVersion here since this value may change in the future.
If an invalid album file is provided, then the default block is executed. We throw an exception to indicate that an unexpected error occurred. Rather than creating a custom exception object here, we opt for the IOException class instead with an appropriate message string.
In case our default clause executes, or if any other unexpected problems occur, we enclose the entire code to read from the file in a try block.
6.7.2OPENING AN ALBUM FILE
The PhotoAlbum.Open method can now be used in a Click handler for the Open menu of our application. We have been using the OpenFileDialog class to open image files. Here we will use it to open album files. As we did for our Save menus, we will preserve the current directory setting to ensure that the Add menu handler opens its file dialog at the most recent location.
OPEN FILE DIALOGS |
191 |
Set the version number of the MyPhotos application to 6.7.
IMPLEMENT A CLICK HANDLER FOR THE OPEN MENU
|
Action |
Result |
|
|
|
1 |
Add a click handler for the |
protected void menuOpen_Click |
|
Open menu item in the |
(object sender, System.EventArgs e) |
|
MainForm class. |
{ |
|
|
|
|
|
|
2 |
Save any existing album |
// Save the existing album, if necessary |
|
before loading the new |
if (_bAlbumChanged && _album.FileName != null) |
|
one. |
{ |
|
menuSave_Click(sender, e); |
|
|
|
|
|
Note: This code is not the |
} |
|
best design. Not only does |
|
|
it discard a newly created |
|
|
album, it forces a save of |
|
|
the current one. We will fix |
|
|
this behavior in chapter 8. |
|
|
|
|
3 |
Create an |
// Allow user to select a new album |
|
OpenFileDialog class to |
OpenFileDialog dlg = new OpenFileDialog(); |
|
select an album file. |
dlg.Title = "Open Album"; |
|
|
|
|
|
dlg.Filter = "Album files (*.abm)|*.abm|" |
|
|
+ "All files (*.*)|*.*"; |
|
|
dlg.InitialDirectory = PhotoAlbum.DefaultDir; |
|
|
dlg.RestoreDirectory = true; |
|
|
|
4 |
Use the PhotoAlbum.Open |
if (dlg.ShowDialog() == DialogResult.OK) |
|
method to read the album. |
{ |
|
|
// Open the new album |
|
|
_album.Open(dlg.FileName); |
|
|
|
5 |
Set the new album name |
_album.FileName = dlg.FileName; |
|
and invalidate the window |
_bAlbumChanged = false; |
|
to draw the initial photo. |
|
|
this.Invalidate(); |
|
|
|
|
|
|
} |
|
|
|
6 |
Dispose of nonmemory |
dlg.Dispose(); |
|
resources used by the |
} |
|
dialog. |
|
|
|
|
Note that our implementation has an unfortunate feature of discarding a new album that has never been saved, and of saving an existing one even when the user does not wish to do so. This might not be the desired behavior, but is okay for this chapter. You may notice that we also do not handle any exceptions that might be raised by the PhotoAlbum.Open method, such as when the selected file does not actually represent a PhotoAlbum object. These problems are both addressed in chapter 8.
TRY IT! If you would like to experiment here, create a version of the album file (use version number 67) that stores the current position in the album. This value should be saved in the album file in the line after the version number before any image files are listed.
192 |
CHAPTER 6 COMMON FILE DIALOGS |