- •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
Now the project should compile with no errors in Visual Studio .NET. If you are not using Visual Studio, multiple files can be included in the library by simply providing the list of files to the compiler. An example of how this might look is shown here.
>csc /target:library /out:MyPhotoAlbum.dll PhotoAlbum.cs Photograph.cs /r:System.dll /r:System.Drawing.dll
Before we deal with the possible exception that can occur in the Photograph.Image property, let’s return to our PhotoAlbum class to make some initial use of the Photograph class.
5.3INTERFACES REVISITED
Back in our PhotoAlbum class, we are ready to implement the interfaces required. As you’ll recall, an interface defines the set of required members, but does not provide any implementation. Supporting an interface requires that we define the class as supporting the interface, and include the required members for that interface within the class.
For the PhotoAlbum class, the CollectionBase class defines itself as supporting the IEnumerable, ICollection, and IList interfaces. An implementation for the single method GetEnumerator required by the IEnumerable interface is provided by CollectionBase. As a result, we are left to implement the ICollection and IList interfaces. A list of ICollection members is provided in the following table:
PhotoAlbum members required for the ICollection interface
|
Name |
Implementation Notes |
|
|
|
|
Count |
This property is provided by CollectionBase. |
|
IsSyncronized |
For simplicity, we will not provide a synchronized interface for |
Properties |
|
the PhotoAlbum class. As a result, this property will always |
|
|
return false. |
|
SyncRoot |
|
|
|
|
Methods |
CopyTo |
|
|
|
|
The IList interface has a slightly longer list of members. Some of them are already provided by the CollectionBase class, but the bulk of them will be implemented using the protected CollectionBase.List property.
PhotoAlbum members required for the IList interface
|
Name |
Implementation Notes |
|
|
|
|
IsFixedSize |
This method will always return false. |
Properties |
IsReadOnly |
This method will always return false. |
|
Item |
This property enables array-style indexing for our class. |
|
|
|
INTERFACES REVISITED |
145 |
PhotoAlbum members required for the IList interface (continued)
|
Name |
Implementation Notes |
|
|
|
|
Add |
|
|
Clear |
This method is provided by CollectionBase. |
|
Contains |
|
Methods |
IndexOf |
|
|
Insert |
|
|
Remove |
|
|
RemoveAt |
This method is provided by CollectionBase. |
|
|
|
We will examine the implementation of these interfaces separately.
5.3.1SUPPORTING THE ICOLLECTION INTERFACE
The implementation of the ICollection members will use the protected List property from our base class, so let’s get to it. We will make these and our IList members virtual to allow any subclass to override them as needed.
Set the version number for the application to 5.3.
SUPPORT THE ICOLLECTION INTERFACE
|
Action |
Result |
|
|
|
1 |
Display the PhotoAlbum.cs file. |
|
|
|
|
2 |
Implement the IsSynchronized |
public virtual bool IsSynchronized |
|
property. |
{ |
|
|
get { return false; } |
|
|
} |
|
|
|
3 |
Implement the SyncRoot property. |
public virtual object SyncRoot |
|
|
{ |
|
|
get { return List.SyncRoot; } |
|
|
} |
|
|
|
4 |
Implement the CopyTo method. |
public virtual void CopyTo |
|
|
(Photograph[] array, int index) |
|
|
{ |
|
|
List.CopyTo(array, index); |
|
|
} |
|
|
Note: We require the array parameter to be an |
|
|
array of Photograph objects. The ICollection |
|
|
interface defines the CopyTo method as |
|
|
CopyTo(Array array, int index). Since a |
|
|
Photograph[] is also an Array, our declaration |
|
|
is an acceptable implementation even though it is |
|
|
more restrictive than the method defined by the |
|
|
interface. |
|
|
|
5.3.2SUPPORTING THE ILIST INTERFACE
Our implementation for IList will be very similar in spirit to our implementation for ICollection. A key difference between the signatures of the IList members and
146 |
CHAPTER 5 REUSABLE LIBRARIES |
our implementation is that we will use the Photograph class explicitly rather than the more generic object. Since a Photograph is still an object instance, a construct that requires an IList instance will still be able to use our PhotoAlbum object.
This may seem a bit boring and tedious, but it needs to be done for a complete implementation. Note that C# does not support C++ style templates at this time, which would have been handy for implementing this and other interfaces.
SUPPORT THE ILIST INTERFACE
|
Action |
Result |
|
|
|
1 |
Display the PhotoAlbum.cs file. |
|
|
|
|
2 |
Implement the IsFixedSize |
public virtual bool IsFixedSize |
|
property. |
{ |
|
|
get { return false; } |
|
|
} |
|
|
|
3 |
Implement the IsReadOnly |
public virtual bool IsReadOnly |
|
property. |
{ |
|
|
get { return false; } |
|
|
} |
|
|
|
4 |
Implement the Item property. |
public virtual Photograph this[int index] |
|
Note: The Item property is the |
{ |
|
get { return (Photograph)(List[index]); } |
|
|
C# indexer, so we simply imple- |
set { List[index] = value; } |
|
ment indexing to support this |
} |
|
property. |
|
|
|
|
5 |
Implement the Add method. |
public virtual int Add(Photograph photo) |
|
|
{ |
|
|
return List.Add(photo); |
|
|
} |
|
|
|
6 |
Implement the Contains |
public virtual bool Contains(Photograph photo) |
|
method. |
{ |
|
|
return List.Contains(photo); |
|
|
} |
|
|
|
7 |
Implement the IndexOf |
public virtual int IndexOf(Photograph photo) |
|
method. |
{ |
|
|
return List.IndexOf(photo); |
|
|
} |
|
|
|
8 |
Implement the Insert method. |
public virtual void Insert |
|
|
(int index, Photograph photo) |
|
|
{ |
|
|
List.Insert(index, photo); |
|
|
} |
|
|
|
9 |
Implement the Remove method. |
public virtual void Remove(Photograph photo) |
|
|
{ |
|
|
List.Remove(photo); |
|
|
} |
|
|
|
These methods simply use the equivalent version in the protected List property, except that our implementation will only accept Photograph objects. The Item property is worth noting since it defines zero-based array-style indexing for our class, such as myAlbum[1] to specify the second Photograph in an album. The syntax
INTERFACES REVISITED |
147 |
defines an indexer for the class. Indexers define array-style access to a class, using a syntax employing access methods similar to the declaration of properties. An indexer is defined using the this keyword to refer to the class itself, with the index variable defining the index value within the definition. In this manner the indexer defines retrieval and assignment access to the array of Photograph objects in the collection. Any collection class can be treated as an indexed array through the use of a similar indexer definition.
public virtual Photograph this[int index]
{
get { return (Photograph)(List[index]); } set ( List[index] = value; }
}
5.3.3IMPLEMENTING ALBUM POSITION OPERATIONS
This is a good place to insert the position operations for tracking the current location within an album. This position will be used by our application to display the current photo from the album as well as other tasks.
From a design perspective, we will use the word “Current” as a prefix for these operations. This is the name of a property used by the IEnumerator interface, and
is consistent with the meaning we intend here. We will add the following members to our class:2
PhotoAlbum position members
Member |
Description |
|
|
CurrentPosition property |
Gets or sets the index of the current position within the album. By |
|
definition, the first position is always zero (0), and the last position is |
|
one less than the number of Photographs in the album. |
CurrentPhoto property |
Gets the Photograph object at the current position. This will use the |
|
CurrentPosition property as an index into the collection to ensure |
|
that we will always retrieve a valid photo. |
CurrentNext method |
Moves the current position to the next photograph. Returns a |
|
boolean indicating if there was a next photo (true) or if the end of |
|
the album has been reached (false). |
CurrentPrevious method |
Moves the current position to the previous photograph. Returns a |
|
boolean indicating if there was a previous photo (true) or if the |
|
beginning of the album has been reached (false). |
|
|
2Some might argue for using the GetEnumerator method to track the position, or for creating a mechanism similar to database cursors to allow an application to track multiple locations within the album at the same time. The former is problematic if the application inserts or removes photos while the enumerator is active. The latter is a good idea, but a bit beyond what we intend to cover in this chapter.
148 |
CHAPTER 5 REUSABLE LIBRARIES |