- •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
This code defines a comparison class for our ListView control. The next step is to hook this into our actual form. This requires that we create an instance of the MyListViewComparer class and assign it as the comparer for our list. Let’s do this first, and then we can handle the ColumnClick event to adjust the comparison settings. This continues our previous steps.
ASSIGN COMPARER TO THE LIST VIEW CONTROL
|
Action |
Result |
|
|
|
15 |
Define a private variable to hold |
private MyListViewComparer _comparer; |
|
the comparer class for the form. |
|
|
|
|
16 |
Create and assign this comparer |
protected override void OnLoad(EventArgs e) |
|
to the view in the OnLoad |
{ |
|
method. |
// Define the list view comparer |
|
_comparer = new |
|
|
|
|
|
Note: This is done at the begin- |
MyListViewComparer(listViewMain); |
|
ning of this method to ensure |
listViewMain.ListViewItemSorter = _comparer; |
|
listViewMain.Sorting = SortOrder.Ascending; |
|
|
the comparer exists during con- |
|
|
. . . |
|
|
trol initialization. |
} |
|
|
|
We now have a comparison class assigned to our view. The ListView control will automatically call this class’s Compare method whenever it must sort the contents of the view. This occurs each time the Sorting property is set to a new value other than None.
We can take advantage of this in our ColumnClick handler to ensure that the list is updated whenever a column is clicked. As we indicated earlier, ColumnClick event handlers receive a ColumnClickEventArgs class as the event parameter. This class defines a Column property containing the index of the selected column in the corresponding list view.
Let’s define this handler to complete our implementation of column sorting.
HANDLE THE COLUMNCLICK EVENT
|
Action |
Result |
|
|
|
17 |
Handle the ColumnClick |
private void listViewMain_ColumnClick |
|
event for the listViewMain |
(object sender, System.Windows. |
|
control. |
Forms.ColumnClickEventArgs e) |
|
{ |
|
|
|
|
|
|
|
18 |
Reset the sorting order for |
SortOrder prevOrder = listViewMain.Sorting; |
|
the control. |
listViewMain.Sorting = SortOrder.None; |
|
|
|
19 |
If the current column was |
if (e.Column == _comparer.SortColumn) |
|
clicked, then invert the |
{ |
|
existing sort order. |
// Switch the sorting order |
|
if (prevOrder == SortOrder.Ascending) |
|
|
|
|
|
|
listViewMain.Sorting = SortOrder.Descending; |
|
|
else |
|
|
listViewMain.Sorting = SortOrder.Ascending; |
|
|
} |
|
|
|
462 |
CHAPTER 14 LIST VIEWS |
HANDLE THE COLUMNCLICK EVENT (continued)
|
Action |
Result |
|
|
|
20 |
Otherwise, sort the control |
else |
|
based on the newly selected |
{ |
|
column. |
// Define new sort column and reset order |
|
_comparer.SortColumn = e.Column; |
|
|
|
|
|
|
listViewMain.Sorting = SortOrder.Ascending; |
|
|
} |
|
|
} |
|
|
|
Twenty steps in one section. That might be a record. Note how we reset the sort order to None at the beginning of the handler. This ensures that the framework will re-sort the contents when we set the actual sort order a few lines later. Without this reset, the control will not invoke the comparer if the sort order is not a new value, such as when two different columns are clicked one after another.
Compile and run to verify that this sorting works as advertised. Make sure you click the Size column to perform integer-based sorting. An example of such a sort in descending order is shown in figure 14.4.
Figure 14.4
In this graphic, the ListView control in the application is sorted by the Size column.
Alternate sorting mechanisms are possible here as well. Later in the chapter, we will see how to sort date and time values in the control.
TRY IT! The AllowColumnReorder property indicates that the user may rearrange the columns by clicking and dragging them with the mouse. Set this property to true to see how this works. What happens when you sort a column after reordering the columns? Note that the ColumnClick event does not occur during a drag, even though the user must click and then release the column header.
This completes our initial discussion of items and subitems in the list view control. The remaining sections examine some of the more common events normally used with this control.
LISTVIEW COLUMNS |
463 |
14.4SELECTION AND EDITING
So far we have created a ListView control in our application and supported column sorting. In this section we’ll look at some of the events used to interact with specific items in the list. Specifically, we will look at adding the following features:
•Viewing the properties associated with a selected item in the list.
•Editing the label of an item in our list.
•Displaying the Photograph objects in the album when the user double-clicks on an item.
The first two topics are covered in this section. The last topic is related to item activation, which is the subject of section 14.5.
14.4.1SUPPORTING ITEM SELECTION
Like the ListBox control, a list view can support single item or multiple item selection. The MultiSelect property is a boolean property that indicates which type of selection to support. We looked at multiple selection within list boxes in chapter 10, so we will stick with single selection in this chapter.
The SelectedIndices property holds the collection of indices corresponding to the selected items in the list. These index values refer to the position of the items within the collection represented by the Items property. The SelectedItems property holds the collection of selected items directly.
Figure 14.5
The properties window displayed for the leeds.abm album.
To make use of the selected item, we will create a menu item to display the properties associated with the selected album, as shown in figure 14.5. The Click event handler for this menu will open the selected album, display the properties dialog for this
464 |
CHAPTER 14 LIST VIEWS |
album, and update both the album and the made by the user.
The following steps explain how to add both the menu and the Click handler.
Set the version number of the MyAlbumExplorer application to 14.4.
|
|
|
|
ADD A MENU TO DISPLAY ALBUM PROPERTIES |
||
|
|
|
|
|
|
|
|
|
|
Action |
Result |
||
|
|
|
|
|
|
|
1 |
In the MainForm.cs [Design] |
|
||||
|
window, add a Properties menu |
|
||||
|
under the Edit menu. |
|
||||
|
|
Settings |
|
|||
|
|
|
|
|
|
|
|
|
Property |
|
Value |
|
|
|
|
(Name) |
|
menuProperties |
|
|
|
|
Text |
|
&Properties… |
|
|
|
|
|
|
|
|
|
2 |
Add a Click event handler for |
private void menuProperties_Click |
||||
|
this menu to display the property |
(object sender, System.EventArgs e) |
||||
|
dialog for the selected album, if |
{ |
||||
|
if (listViewMain.SelectedItems.Count <= 0) |
|||||
|
any. |
|
|
|
||
|
|
|
|
return; |
||
|
Note: We separate the display |
ListViewItem item |
||||
|
logic into a separate DisplayAl- |
|||||
|
= listViewMain.SelectedItems[0]; |
|||||
|
bumProperties method in case |
DisplayAlbumProperties(item); |
||||
|
we ever want to call it from other |
} |
||||
|
portions of our application. |
|
||||
|
|
|
|
|
|
|
3 |
In order to locate the album file |
private void LoadAlbumData(string dir) |
||||
|
name in our new method, record |
{ |
||||
|
the album file name in the Tag |
. . . |
||||
|
foreach (string s in albumFiles) |
|||||
|
property associated with each list |
|||||
|
{ |
|||||
|
item in the LoadAlbumData |
. . . |
||||
|
method. |
|
|
|
if (album != null) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
item.Tag = album.FileName; |
|
|
|
|
|
|
item.ImageIndex = MainForm.AlbumIndex; |
|
|
|
|
|
|
. . . |
|
|
|
|
|
|
|
4 |
Add the |
|
|
|
private void DisplayAlbumProperties |
|
|
DisplayAlbumProperties |
(ListViewItem item) |
||||
|
{ |
|||||
|
method to display the album |
|||||
|
|
|||||
|
dialog. |
|
|
|
|
|
|
|
|
|
|
|
|
5 |
Implement this method by |
string fileName = item.Tag as string; |
||||
|
obtaining the file name for the |
|
||||
|
selected album. |
|
||||
|
|
|
|
|
|
|
6 |
Try to open the album |
PhotoAlbum album = null; |
||||
|
corresponding to this file name. |
if (fileName != null) |
||||
|
|
|
|
|
|
album = this.OpenAlbum(fileName); |
|
|
|
|
|
|
|
SELECTION AND EDITING |
465 |
ADD A MENU TO DISPLAY ALBUM PROPERTIES (continued)
|
Action |
Result |
|
|
|
7 |
Display an error message if the |
if (album == null) |
|
album could not be opened. |
{ |
|
Note: Here and throughout the |
MessageBox.Show("The properties for " |
|
+ "this album cannot be displayed."); |
|
|
remainder of the book, we use |
return; |
|
the simplest form of the Mes- |
} |
|
|
|
|
sageBox dialog. Feel free to use |
|
|
an alternate form if you prefer. |
|
|
See chapter 8 for detailed infor- |
|
|
mation on the MessageBox |
|
|
class. |
|
|
|
|
8 |
Display the AlbumEditDlg if the |
using (AlbumEditDlg dlg |
|
album is opened successfully. |
= new AlbumEditDlg(album)) |
|
|
{ |
|
|
|
9 |
If any changes are made by the |
if (dlg.ShowDialog() == DialogResult.OK) |
|
user, save these changes into the |
{ |
|
album file. Catch any errors that |
// Save changes made by the user |
|
try |
|
|
occur. |
|
|
{ |
|
|
|
album.Save(); |
|
|
} |
|
|
catch (Exception) |
|
|
{ |
|
|
MessageBox.Show("Unable to save " |
|
|
+ "changes to album."); |
|
|
return; |
|
|
} |
|
|
|
10 |
Also update any subitem text that |
// Update subitem settings |
|
might be affected by the user’s |
item.SubItems[MainForm. |
|
changes. |
AlbumTitleColumn].Text |
|
= album.Title; |
|
|
|
|
|
|
bool hasPwd = (album.Password != null) |
|
|
&& (album.Password.Length > 0); |
|
|
item.SubItems[MainForm. |
|
|
AlbumPwdColumn].Text |
|
|
= (hasPwd ? "y" : "n"); |
|
|
} |
|
|
} |
|
|
|
11 |
Dispose of the album at the end |
album.Dispose(); |
|
of the method. |
} |
|
|
|
We employ the using statement to ensure that our dialog is properly disposed of at the end of the handler. Also note how multiple exceptional handling blocks are used to catch errors that occur. You may wonder if it is expensive to perform such operations, especially if you are familiar with exception-handling mechanisms in languages like C and C++ where it indeed can be an expensive proposition to call try multiple times. In C#, the exception handling is built into the language and the compiler, so checking for exceptions as we do here is not much more expensive than an if statement. The expense comes if an exception actually occurs, since the compiler must
466 |
CHAPTER 14 LIST VIEWS |
then construct the Exception object, unravel the call stack and clean up any objects as required, plus locate the appropriate catch block for the particular exception.
The fact that exception clean up can impact a program’s performance is one more reason to ensure that you throw exceptions only for truly exceptional conditions. Common problems or situations should be handled through the use of an error code. As a case in point, this is one reason why file-related read and write methods in the
.NET Framework do not raise an exception when the end of a file is reached.
Back to our code, this discussion tells us that our use of try and catch here should not affect our performance very much since we do not normally expect an exception to occur other than when opening an invalid album. We could improve the performance if we kept track of the invalid albums during the OnLoad method, since then we would not need to re-open these albums again here. We will not actually do this here, but it was worth a mention.
The remainder of the previous code is fairly self-explanatory. One other point worth mentioning is our use of the Tag property. This works well in our DisplayAlbumProperties method since all we need to keep track of is the album’s file name. It is also possible here to assign a PhotoAlbum instance to the Tag property rather than a string instance, although this requires extra memory and other resources to maintain the album for each item in memory.
An alternative approach often used to track more complex relationships is to derive a new class from the ListViewItem class. For our application, an excerpt of such a class might look something like the code shown in listing 14.1. Since this class is a ListViewItem object, instances of it can be assigned to and manipulated within the ListView control. Whenever the PhotoAlbum object for an album is required, a list view item can be downcast to the PhotoAlbumListItem class, where the Album property and other members may be used to manipulate the album.
Listing 14.1 Example deriving a new class from ListViewItem (not our approach)
public class PhotoAlbumListItem : ListViewItem, IDisposable
{
private string _fileName; private PhotoAlbum _album;
PhotoAlbumListItem(string file)
{
_fileName = file; _album = null;
}
public void Dispose()
{
// Dispose implementation
. . .
}
public PhotoAlbum Album
SELECTION AND EDITING |
467 |
{
get
{
if (_album == null)
{
_album = new PhotoAlbum(); _album.Open(_fileName);
}
return _album;
}
}
// Other methods as required
. . .
}
For our purposes the use of a simple string value in the Tag property was sufficient to display the album’s properties dialog. Another feature worth supporting here is the ability to edit item labels.
14.4.2SUPPORTING LABEL EDITS
Editing an item label in place is one of the advantages the ListView class has over ListBox objects. In our application it would be nice if the user could edit the album name in order to rename an album file. This section will show how to support this feature.
Label editing is disabled by default, and turned on by setting the LabelEdit property to true. An actual edit of an item is initiated by the BeginEdit method of the ListViewItem class. The corresponding ListView control receives two events during the editing process. The BeforeLabelEdit event occurs before the edit process begins, while the AfterLabelEdit event occurs when the user completes the edit by pressing the Enter key or clicking outside of the edit area. Event handlers for both events receive the LabelEditEventArgs class as their event handler. See .NET Table 14.7 for an overview of this class.
We will allow an item to be edited in two ways. The first way is through a Name menu under the top-level Edit menu, and the second way is by selecting an item and pressing the F2 key. This matches the keyboard shortcut supported by Windows Explorer, so it seems appropriate here.
In a production environment, we would probably handle both events in our application. In the BeginLabelEdit event handler we would make sure the album is valid and can be successfully opened. This provides some assurance that the edit will be successful before the user begins typing. The AfterLabelEdit event handler would update the album with a new title and store the album to disk. It would also update the album file on disk with the change.
468 |
CHAPTER 14 LIST VIEWS |