- •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
SUPPORT THE IDISPOSABLE INTERFACE (continued)
|
Action |
Result |
|
|
|
4 |
Implement the Dispose method for |
private bool _disposing = false; |
|
the PhotoAlbum class. |
public void Dispose() |
|
Note: We dispose of each Photo- |
{ |
|
if (!_disposing) |
|
|
graph in the album as well here.” |
|
|
{ |
|
|
|
|
|
|
_disposing = true; |
|
|
foreach (Photograph photo in this) |
|
|
{ |
|
|
photo.Dispose(); |
|
|
} |
|
|
Clear(); |
|
|
} |
|
|
} |
|
|
|
5 |
Ensure that the album is properly |
protected override void OnClear() |
|
disposed of when its contents are |
{ |
|
cleared. |
_currentPos = 0; |
|
this.Dispose(); |
|
|
|
|
|
How-to |
base.OnClear(); |
|
Update the OnClear method to |
} |
|
|
|
|
dispose of the contents. |
|
|
|
|
Our objects can now dispose of their contents properly. Be aware that it may not always be a good idea to dispose of contained objects as we do for the PhotoAlbum class here. There are times when an object in a list may be in use elsewhere in the program, and it is best to let the caller or the garbage collector decide when and how to dispose of any contents. For example, if a single Photograph object could be stored in two PhotoAlbum objects at the same time, then our PhotoAlbum.Dispose method would not be appropriate. We will enforce the rule that a single Photograph can only be a member of a single album, so the implementation presented here will work just fine.
We have one more change to make before going on to chapter 6.
5.4.4ASSOCIATING A FILE NAME WITH AN ALBUM
One final addition that hasn’t fit anywhere else in this chapter is the ability to assign a file name to an album. This will come in handy when we save and open albums in chapter 6. We will do this by providing a FileName property in the class, as detailed by the following table.
ADD A FILE NAME PROPERTY FOR AN ALBUM
|
Action |
Result |
|
|
|
1 |
In the PhotoAlbum.cs file, |
private string _fileName = null; |
|
create a private field to |
|
|
store the file name. |
|
|
|
|
ROBUSTNESS ISSUES |
159 |
ADD A FILE NAME PROPERTY FOR AN ALBUM (continued)
|
Action |
Result |
|
|
|
2 |
Create a public property to |
public string FileName |
|
retrieve or define this |
{ |
|
value. |
get { return _fileName; } |
|
set { _fileName = value; } |
|
|
|
|
|
|
} |
|
|
|
3 |
Reset this value when the |
protected override void OnClear() |
|
album is cleared. |
{ |
|
|
_currentPos= 0; |
|
|
_fileName = null; |
|
|
this.Dispose(); |
|
|
base.OnClear(); |
|
|
} |
|
|
|
Note that we permit a nonexistent file name to be assigned in this property. This allows an album name to be assigned before any data is actually saved into the file.
This completes the implementation of the PhotoAlbum and Photograph classes, at least for now. As usual, we finish this chapter with a quick summary of our accomplishments.
5.5RECAP
In this chapter we created an external library that applications everywhere can use when a photo album is required. We implemented a Photograph class to encapsulate a photographic image, and a PhotoAlbum class to encapsulate a collection of Photograph objects. Along the way we examined interfaces, .NET collection classes, custom bitmap creation, internals of the Object class, and the IDisposable interface.
The MyPhotoAlbum.dll library is ready for use in our MyPhotos application. Integrating this library into our application is the topic of our next chapter. This will allow us to support multiple images in our application, and set the stage for future changes to come.
More .NET For questions on C#, Windows Forms, and other aspects of .NET, Microsoft provides a number of Internet newsgroups on a variety of topics. These are available at Microsoft’s News Server at news.microsoft.com. Among the newsgroups provided are microsoft.public.dotnet.framework.windowsforms for questions about Windows Forms application development, and microsoft.public.dotnet.languages.csharp for questions about the C# programming language.
160 |
CHAPTER 5 REUSABLE LIBRARIES |
C H A P T E R |
6 |
|
|
Common file dialogs
6.1 |
Design issues 162 |
6.5 |
Files and paths |
175 |
6.2 |
Multiple file selection 166 |
6.6 |
Save file dialogs |
181 |
6.3 |
Paint events 169 |
6.7 |
Open file dialogs 189 |
|
6.4 |
Context menus revisited 173 |
6.8 |
Recap 193 |
|
In the previous chapter we created the Photograph and PhotoAlbum classes as a way to encapsulate a photographic image and a collection of photographs. In this chapter we make use of these classes in our application to display a photo album to the user. We will stick with our model of one photo at a time, but allow a user to move forward and backward within the album. This will permit us to focus on integrating the library without too many changes to the user interface.
In future chapters, we will expand our class library with additional functionality such as storing the date a photograph was taken, or the name of a photographer. Adding such features to a photo album will take some work by the user, which we would not want to throw away when the program exits. As a result, before any of these additional features really make sense, we need to store our photo album on the disk so it can be used again (and again and again).
How will we store our album on disk? In a file, of course, to match the chapter title. Specifically, this chapter will show how to perform the following tasks:
•Use the PhotoAlbum and Photograph classes to display, navigate, and manage a set of photographs in the MyPhotos application.
•Allow multiple images to be loaded at once using the OpenFileDialog class.
161
•Save the current album using the SaveFileDialog class.
•Open a previously saved album using the OpenFileDialog class.
Figure 6.1 shows how our application will look by the end of this chapter, with the new File menu displayed. Note that we have also added an Edit menu and a new status bar panel showing the current position within the album. In the figure, the third of a total of four photographs in the album is shown.
Figure 6.1
In this chapter we implement a more traditional File menu structure for our application.
6.1DESIGN ISSUES
The changes planned for this chapter require that we rewrite our menu bar. Before we plunge ahead, let’s do some brief design work to lay out this new main menu. It is always a good idea to sketch your graphical elements up front. You can even do this on paper. The point is to have in mind the graphical interface you wish to implement before you start writing code. While it is always possible to move menus and other objects around, it can also waste a lot of time. This is especially true if the application has to be approved by a manager, the customer, or anyone else. Doing a quick sketch on paper creates a basis for discussion and allows initial thoughts and ideas to be aired before a more formal design document or any code is written.
6.1.1CHANGING THE MENU BAR
While we are not doing a formal design here, let’s at least write down the new menu structure we will implement. As shown in the following table, in addition to the File menu changes, we will also add an Edit menu to our application.
162 |
CHAPTER 6 COMMON FILE DIALOGS |