- •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
displays descriptive text about the photo, and automatically scrolls if the text becomes too long. The following steps add this control to our dialog:
ADD A MULTILINE TEXTBOX TO THE PHOTOEDITDLG FORM
|
|
|
Action |
|
|
|
Result |
|
|
|
|
|
|
|
|
|
|
1 |
|
Add the Notes label to the |
The AutoSize property causes the label to resize to exactly fit |
|||||
|
|
PhotoEditDlg form in the |
its Text value. |
|||||
|
|
PhotoEditDlg.cs [Design] |
|
|||||
|
|
window.. |
|
|
|
|
||
|
|
|
Settings |
|
||||
|
|
|
|
|
|
|
|
|
|
|
|
Property |
|
Value |
|
||
|
|
|
AutoSize |
|
True |
|
||
|
|
|
TabIndex |
|
4 |
|
|
|
|
|
|
Text |
|
Notes: |
|
||
|
|
|
|
|
|
|
|
|
2 |
|
Add the multiline TextBox |
|
|||||
|
|
control to the form. |
|
|||||
|
|
|
Settings |
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
Property |
|
Value |
|
||
|
|
|
(Name) |
|
txtNotes |
|
||
|
|
|
AcceptsReturn |
|
True |
|
||
|
|
|
Multiline |
|
True |
|
||
|
|
|
ScrollBars |
|
Vertical |
|
||
|
|
|
TabIndex |
|
5 |
|
|
|
|
|
|
Text |
|
|
|
|
|
|
|
|
|
|
|
|
|
Note: The Multiline property must be set to true |
|
|
|
|
|
|
|
|
before the control can be resized to contain multiple lines |
|
|
|
|
|
|
|
|
of text. |
|
|
|
|
|
|
|
|
The AcceptsReturn property causes the control to |
|
|
|
|
|
|
|
|
treat an Enter key as a new line rather than allowing the |
|
|
|
|
|
|
|
|
parent form to invoke the OK button. |
|
|
|
|
|
|
|
|
|
Our form is now ready, except for the internal logic to process the user’s changes. Since our dialog is intended to edit a Photograph object within a PhotoAlbum
collection, we need a reference to the associated PhotoAlbum object within the dialog. We should also implement the methods necessary to handle the OK and Reset buttons, namely the ResetSettings and SaveSettings methods provided by the
BaseEditDlg class.
The following steps detail these changes:
LABELS AND TEXT BOXES |
283 |
INTERACTING WITH THE PHOTOALBUM OBJECT
|
Action |
Result |
|
|
|
3 |
In the PhotoEditDlg.cs file add a |
private PhotoAlbum _album; |
|
private PhotoAlbum variable to |
|
|
hold the album containing the |
|
|
photo to display. |
|
|
|
|
4 |
Modify the constructor to accept |
public PhotoEditDlg(PhotoAlbum album) |
|
a PhotoAlbum parameter. |
{ |
|
|
|
5 |
Within the constructor, set the |
// This call is required . . . . |
|
album variable and call |
InitializeComponent(); |
|
ResetSettings to initialize the |
// Initialize the dialog settings |
|
dialog’s controls. |
|
|
_album = album; |
|
|
|
ResetSettings(); |
|
|
} |
|
|
|
6 |
Implement the ResetSettings |
protected override void ResetSettings() |
|
method to set the controls to |
{ |
|
their corresponding settings in |
Photograph photo = _album.CurrentPhoto; |
|
|
|
|
the current photograph. |
if (photo != null) |
|
|
{ |
|
|
txtPhotoFile.Text = photo.FileName; |
|
|
txtCaption.Text = photo.Caption; |
|
|
txtDate.Text |
|
|
= photo.DateTaken.ToString(); |
|
|
txtPhotographer.Text = photo.Photographer; |
|
|
this.txtNotes.Text = photo.Notes; |
|
|
} |
|
|
} |
|
|
|
7 |
Implement SaveSettings to |
protected override bool SaveSettings() |
|
save the contents of the form to |
{ |
|
the current photograph. |
Photograph photo = _album.CurrentPhoto; |
|
|
|
|
Note: Here, the settings are |
if (photo != null) |
|
always stored successfully, so |
{ |
|
photo.Caption = txtCaption.Text; |
|
|
this method always returns |
|
|
// Ignore txtDate setting for now |
|
|
true. |
photo.Photographer = txtPhotographer.Text; |
|
|
photo.Notes = txtNotes.Text; |
|
|
} |
|
|
return true; |
|
|
} |
|
|
|
Our dialog is complete, at least for now. Applications can use it to display and modify information about a photograph. The one exception is the date a photograph was taken. While it is certainly possible to convert a string provided by the user into a DateTime structure, this is not really the best way to specify a date on a form. Instead, the DateTimePicker control is provided especially for this purpose. We will look at this control in chapter 11, and simply ignore the value of txtDate for now.
The next step is to use this new dialog in our main application. This is the topic of the next section.
284 |
CHAPTER 9 BASIC CONTROLS |
9.2.4ADDING PHOTOEDITDLG TO OUR MAIN FORM
Now that our new dialog is ready, we need to display it in our MyPhotos application.
This section integrates the dialog into our application, much like we integrated the CaptionDlg form in chapter 8.
The CaptionDlg form does present a slight problem, in that it already allows the caption to be edited, just like our new PhotoEditDlg form. We could keep this dialog around and provide two ways to edit a photograph’s caption. This might be a little confusing to users, so we will instead remove CaptionDlg from our application.
The step to remove this dialog follows. We will integrate the PhotoEditDlg dialog into our application in a moment.
Set the version number of the MyPhotos application to 9.2.
|
REMOVE THE CAPTIONDLG FORM |
|
|
|
|
|
Action |
Result |
|
|
|
1 |
In the Solution Explorer window, delete |
|
|
the CaptionDlg form. |
|
|
How-to |
|
|
a. Right-click on the CaptionDlg.cs file. |
|
|
b. Select Delete from the popup menu. |
|
|
c. Click OK in the confirmation box. |
|
|
Alternately |
After clicking OK, the CaptionDlg.cs class is |
|
Click on the file and press the Delete key. |
removed from the project and deleted from the |
|
|
file system. |
|
|
|
With the caption dialog gone, our way is clear to display the PhotoEditDlg form from our main window. We will reuse the menuCaption menu for this purpose, renamed and revamped by the following steps:
LABELS AND TEXT BOXES |
285 |
DISPLAY THE PHOTOEDITDLG FORM FROM THE MAIN WINDOW
|
|
|
Action |
Result |
||
|
|
|
|
|
|
|
2 |
Double-click the MainForm.cs file in |
The Windows Forms Designer window appears for |
||||
|
the Solution Explorer window. |
this form. |
||||
|
|
|
|
|
|
|
3 |
Modify the properties for the Caption |
|
||||
|
menu item under the Edit menu. |
|
||||
|
|
Settings |
|
|||
|
|
|
|
|
|
|
|
|
Property |
|
Value |
|
|
|
|
(Name) |
|
menuPhotoProp |
|
|
|
|
Text |
|
&Photo |
|
|
|
|
|
|
Properties… |
|
|
|
Note: We could elect to use this |
|
||||
|
menu under its previous name. This |
|
||||
|
could prove confusing in the future, so |
|
||||
|
we instead rename the control in line |
|
||||
|
with its new purpose. |
|
||||
|
|
|
|
|
|
|
4 |
Rename the Click event for this |
|
||||
|
menu to menuPhotoProp_Click. |
|
||||
|
|
|
|
|
|
|
5 |
Replace the old handler with an |
private void menuPhotoProp_Click |
||||
|
implementation to display the |
(object sender, System.EventArgs e) |
||||
|
PhotoEditDlg form. |
{ |
||||
|
if (_album.CurrentPhoto == null) |
|||||
|
|
|
|
|
|
|
|
Note: The old handler was called |
return; |
||||
|
menuCaption_Click. |
using (PhotoEditDlg dlg |
||||
|
|
|
|
|
|
|
|
|
|
|
|
|
= new PhotoEditDlg(_album)) |
|
|
|
|
|
|
{ |
|
|
|
|
|
|
if (dlg.ShowDialog() |
|
|
|
|
|
|
== DialogResult.OK) |
|
|
|
|
|
|
{ |
|
|
|
|
|
|
_bAlbumChanged = true; |
|
|
|
|
|
|
sbpnlFileName.Text |
|
|
|
|
|
|
= _album.CurrentPhoto.Caption; |
|
|
|
|
|
|
statusBar1.Invalidate(); |
|
|
|
|
|
|
} |
|
|
|
|
|
|
} |
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
6 |
Update the Popup event handler for |
private void menuEdit_Popup |
||||
|
the Edit menu to use the new menu. |
(object sender, System.EventArgs e) |
||||
|
|
|
|
|
|
{ |
|
|
|
|
|
|
menuPhotoProp.Enabled |
|
|
|
|
|
|
= (_album.Count > 0); |
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
Since the dialog itself handles the initialization and storage of any changes made by the user, and the using statement disposes of the dialog when we are finished, there is not much work required by our handler. When the user clicks OK, we mark that the album has changed and update the status bar with any new caption entered by the user.
286 |
CHAPTER 9 BASIC CONTROLS |
So let’s see if your code actually works. Compile and run the application and open a previously saved album file. Display the Photo Properties dialog. Note in particular the following features:
•The differences between the read-only and editable text boxes.
•Label text cannot be highlighted, while text within text boxes can, even when read-only.
•Use the access key for a label and notice how the following text box receives focus.
•Press the Enter key while editing a single-line text box. The dialog behaves as if you had clicked the OK button.
•Press the Enter key while editing within the Notes text box. Since we set the AcceptsReturn property to true, this adds a new line within the Notes box and does not deactivate the window.
•Right-click on any text box. The default context menu will appear. This context menu contains various commands for editing text, and is shown in figure 9.3. The items in this menu correspond to methods in the TextBoxBase class, as shown in .NET Table 9.2.
While our form is working just fine, there are some features missing that might make our dialog a little more friendly. These are the subject of the next section.
Figure 9.3
The standard context menu for TextBox controls, shown here for the Date Taken text box, disables commands that are not currently available.
9.2.5USING TEXTBOX CONTROLS
So let’s add some interesting features to our text boxes. Most of the events for TextBox controls are inherited from the Control and TextBoxBase classes. Members
LABELS AND TEXT BOXES |
287 |
specific to the TextBox class appear in .NET Table 9.3. Here we will look more closely at the KeyPress event and the TextChanged event.
The keyboard events inherited from the Control class are especially interesting, and consist of the KeyDown, KeyPress, and KeyUp events. These events are inherited from the Control class, and occur when a key on the keyboard is pushed down and released while the control has focus. The KeyDown event occurs when the key is first pressed. The KeyPress event activates while the key is held down and repeats while the key remains held down. The KeyUp event occurs when the key is released. These events can be used to fine-tune your interfaces as the user types on the keyboard.
.NET Table 9.3 TextBox class
The TextBox class represents a TextBoxBase control that displays a single font. This control is part of the System.Windows.Forms namespace, and inherits from the TextBoxBase control. Through its parent class, text boxes can support single or multiple lines, and interact with the clipboard to cut, copy, or paste text.
|
AcceptsReturn |
Gets or sets whether the Enter key in a multiline |
|
|
text box adds a new line of text or activates the |
|
|
default button for the form. |
|
CharacterCasing |
Gets or sets how the control modifies the case |
|
|
of entered characters. This can be used to |
|
|
display all uppercase or lowercase letters in the |
|
|
text box. |
Public Properties |
PasswordChar |
Gets or sets the character used to mask the text |
|
||
|
|
display in the control. When this property is set, |
|
|
cutting or copying to the clipboard is disabled. |
|
ScrollBars |
Gets or sets which scrollbars should appear in a |
|
|
multiline text box. |
|
TextAlign |
Gets or sets how displayed text is aligned within |
|
|
the control. |
|
|
|
Public Events |
TextAlignChanged |
Occurs when the TextAlign property has |
|
changed. |
|
|
|
|
|
|
|
We will look at the keyboard events in more detail in chapter 12, but let’s do a quick example here. Suppose we wanted the Caption property to only contain letters or numbers. No punctuation characters and no symbols. The KeyPress event receives keyboard characters as they are typed, and allows the event handler to handle or ignore them. The KeyPressEventArgs class is used with this event, and provides a KeyChar property to get the character pressed, and a Handled property to get or set whether the character has been handled. If Handled is set to true, then the control will not receive the character.
The obvious, albeit incorrect, way to implement such a handler would be as follows:
private void txtCaption_KeyPress(object sender, KeyPressEventArgs e)
{
288 |
CHAPTER 9 BASIC CONTROLS |