- •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
///<summary>
///Required method for Designer support - do not modify
///the contents of this method with the code editor.
///</summary>
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
. . .
}
#endregion
. . .
}
}
Take a look at the properties for the PhotoEditDlg object. The form has inherited all of the settings from our BaseEditDlg form to make it into a dialog box. The buttons and panel from the base class appear on the form as well, and you can examine the properties for the individual buttons. Note in particular that the OK, Reset, and Cancel buttons are private and cannot be modified, while the protected Panel can.
We will leave the topic of inherited forms for now and move on to specific controls for our PhotoEditDlg form. Before we do, it is worth realizing how powerful this feature really is. For example, a standard form for a database table could be created. Applications that use this table can customize the form for their specific needs, or libraries that extend the existing database can build a new form based on the original. In many cases, changes to the original database can be encoded in the base class in such a way that no changes are required in the inherited forms.
When you need a set of forms in your application based on a common concept or theme, consider creating a base form from which other forms can be derived.
9.2LABELS AND TEXT BOXES
In our MyPhotos application, we have already used the Label and TextBox classes while creating dialog boxes in chapter 8. Here we will look at these classes in a bit more detail as we place them on our PhotoEditDlg form.
To do this, we need to come up with some reasonable properties in our
graph class that will facilitate the creation of these and other controls. The following features will serve our purposes rather well:
•Caption—a caption for the photo. We created this property in chapter 8.
•Date—the date the photograph was taken. We will present this as a string on our form here, and convert our dialog to use the DateTimePicker control in chapter 11.
•Photographer—the person who took the photo. For now, we will treat this setting as a string. Later in the book this setting will be taken from a list of possible photographers.
•Notes—random notes or other comments about the photograph.
LABELS AND TEXT BOXES |
271 |
A dialog to support these new settings is shown in figure 9.2. This dialog will be constructed and discussed over the next few sections. In this section we will create the infrastructure required in the Photograph class to support these new settings, add the required controls to the dialog, and invoke the dialog from the main form of our MyPhotos class. We also look at some of the settings and events provided by the TextBox class for modifying the behavior or appearance of the control.
We will start with the changes required in our Photograph class.
Figure 9.2
Our Photo Properties dialog adds Label and Textbox controls to our inherited form.
9.2.1EXPANDING THE PHOTOGRAPH CLASS
In order to support the date, photograph, and notes settings in our photos, we need to make a few changes. This section adds these features to our Photograph object, as well as the ability to read and write photographs, and update the Save and Open methods in our PhotoAlbum class.
We begin with some variables to hold these values and properties to provide external access.
Set the version number of the MyPhotoAlbum library to 9.2.
ADD NEW MEMBERS TO THE PHOTOGRAPH CLASS
|
Action |
Result |
|
|
|
1 |
In the Photograph.cs file, add |
. . . |
|
some variables to hold the new |
private string _caption; |
|
settings. |
private DateTime _dateTaken; |
|
private string _photographer; |
|
|
|
|
|
Note: The DateTime structure |
private string _notes; |
|
used here represents a spe- |
|
|
cific day and time. |
|
|
|
|
272 |
CHAPTER 9 BASIC CONTROLS |
ADD NEW MEMBERS TO THE PHOTOGRAPH CLASS (continued)
|
Action |
Result |
|
|
|
2 |
Initialize these new settings in |
public Photograph(string fileName) |
|
the constructor. |
{ |
|
|
_fileName = fileName; |
|
|
_bitmap = null; |
|
|
_caption = Path. |
|
|
GetFileNameWithoutExtension(fileName); |
|
|
_dateTaken = DateTime.Now; |
|
|
_photographer = "unknown"; |
|
|
_notes = "no notes provided"; |
|
|
} |
|
|
|
3 |
Add properties to set and |
public DateTime DateTaken |
|
retrieve these values. |
{ |
|
Note: A Caption property was |
get { return _dateTaken; } |
|
set { _dateTaken = value; } |
|
|
added in chapter 8, and is not |
} |
|
shown here. |
public string Photographer |
|
|
|
|
|
{ |
|
|
get { return _photographer; } |
|
|
set { _photographer = value; } |
|
|
} |
|
|
public string Notes |
|
|
{ |
|
|
get { return _notes; } |
|
|
set { _notes = value; } |
|
|
} |
|
|
|
This code is similar to member fields and properties we have seen before, except for the DateTime structure. This structure represents an instant in time measured in 100 nanosecond units since 12:00:00 AM on January 1, 0001, with a maximum value of 11:59:59 PM on December 31, 9999. Each nanosecond unit of time is called a tick. Members of this structure allow you to add, subtract, format, and otherwise manipulate date and time values. A related TimeSpan structure represents an interval of time. You can look up these structures in the .NET Framework documentation for more information on these types.
With our fields and properties defined, we next need to store and retrieve these values in the Save and Open methods of our PhotoAlbum class. Since the Photograph class is becoming a bit more complex, we will create Read and Write methods in this class to encapsulate the logic required. The Write method will store a photo into an open StreamWriter object, while various Read methods will accept an open
StreamReader and return a Photograph object.
In our PhotoAlbum class, we will use these new methods to save and load a new version of our album file. It will be version 92, to match the current section of the book.
Let's continue our previous steps and create Read and Write methods in our
Photograph class.
LABELS AND TEXT BOXES |
273 |
ADD READ AND WRITE METHODS TO THE PHOTOGRAPH CLASS
|
Action |
Result |
|
|
|
4 |
Create a public Write method in the |
public void Write(StreamWriter sw) |
|
Photograph.cs file to store a |
{ |
|
Photograph into a given file. |
// First write the file and caption. |
|
sw.WriteLine(this.FileName); |
|
|
|
|
|
How-to |
sw.WriteLine(this.Caption); |
|
|
|
|
a. Store the file name, caption, and |
// Write the date and photographer |
|
photographer as a string. |
sw.WriteLine(this.DateTaken.Ticks); |
|
b. Convert the DateTime to a num- |
sw.WriteLine(this.Photographer); |
|
|
|
|
ber of ticks and store this value. |
// Finally, write any notes |
|
c. Since the notes may span multiple |
sw.WriteLine(this.Notes.Length); |
|
lines, store the length of this string |
sw.Write(this.Notes.ToCharArray()); |
|
sw.WriteLine(); |
|
|
and write its value as an array of |
|
|
} |
|
|
characters. |
|
|
|
|
5 |
Create a ReadVersion66 and |
static public Photograph |
|
ReadVersion83 method to read in |
ReadVersion66(StreamReader sr) |
|
the data in the existing formats. |
{ |
|
String name = sr.ReadLine(); |
|
|
|
|
|
Note: These methods are static |
if (name != null) |
|
since they create a new Photograph |
return new Photograph(name); |
|
else |
|
|
instance from the data provided by |
|
|
return null; |
|
|
the given stream. |
} |
|
|
static public Photograph |
|
|
ReadVersion83(StreamReader sr) |
|
|
{ |
|
|
String name = sr.ReadLine(); |
|
|
if (name == null) |
|
|
return null; |
|
|
Photograph p = new Photograph(name); |
|
|
p.Caption = sr.ReadLine(); |
|
|
return p; |
|
|
} |
|
|
|
274 |
CHAPTER 9 BASIC CONTROLS |
ADD READ AND WRITE METHODS TO THE PHOTOGRAPH CLASS (continued)
|
Action |
Result |
|
|
|
6 |
Create a static ReadVersion92 |
static public Photograph |
|
method to read in a Photograph for |
ReadVersion92(StreamReader sr) |
|
our new version 92 of an album file. |
{ |
|
// Use ReadVer83 for file and caption |
|
|
|
|
|
How-to |
Photograph p = ReadVersion83(sr); |
|
if (p == null) |
|
|
a. Load the file name and caption |
|
|
return null; |
|
|
using the ReadVersion83 |
|
|
method. |
// Read date (may throw FormatException) |
|
b. Read the date as a string and con- |
string data = sr.ReadLine(); |
|
long ticks = Convert.ToInt64(data); |
|
|
vert it to a long integer to instanti- |
p.DateTaken = new DateTime(ticks); |
|
ate a DateTime object. |
// Read the photographer |
|
c. Read the photographer as a string. |
|
|
p.Photographer = sr.ReadLine(); |
|
|
d. For the notes, read in the number |
// Read the notes size |
|
of characters and use this value to |
|
|
data = sr.ReadLine(); |
|
|
read an equivalent-sized array of |
|
|
int len = Convert.ToInt32(data); |
|
|
characters. This array can then be |
|
|
used to create a string. |
// Read the actual notes characters |
|
e. After the Notes property is set, a |
char[] notesArray = new char[len]; |
|
sr.Read(notesArray, 0, len); |
|
|
final ReadLine call is required to |
p.Notes = new string(notesArray); |
|
clear the final line in preparation for |
sr.ReadLine(); |
|
reading the next Photograph |
return p; |
|
object. |
|
|
} |
|
|
|
|
7 |
Create a public delegate to use |
public delegate Photograph |
|
when selecting the appropriate |
ReadDelegate(StreamReader sr); |
|
reader. |
|
|
|
|
Before we update the Save and Open methods in the PhotoAlbum class, a short discussion of our sudden use of the delegate keyword is in order.
We briefly mentioned in chapter 1 that a delegate acts much like a function pointer in C++. It identifies the signature for a method without actually defining a method. The advantage of C# delegates is that they are type safe. It is impossible to assign a nonconforming method to a delegate.
In our code, we create a delegate called ReadDelegate. This delegate encapsulates methods that accept a single StreamReader parameter and return a Photograph object. It just so happens that this matches the signature of the three read methods we created in the prior steps. This delegate can be used to great advantage when opening an album. Let’s see how this looks.
LABELS AND TEXT BOXES |
275 |