- •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
ADD THE SUBITEMS FOR EACH ITEM IN THE LIST
|
Action |
Result |
|
|
|
1 |
Locate the LoadAlbumData |
private void LoadAlbumData(string dir) |
|
method in the MainForm.cs |
{ |
|
source code window. |
. . . |
|
|
|
|
|
|
2 |
When the album is opened |
foreach (string s in albumFiles) |
|
successfully, create the three |
{ |
|
subitems using the |
. . . |
|
ListViewItem item = new ListViewItem(); |
|
|
PhotoAlbum object. |
|
|
|
|
|
|
item.Text |
|
|
= Path.GetFileNameWithoutExtension(s); |
|
|
if (album != null) |
|
|
{ |
|
|
item.ImageIndex = MainForm.AlbumIndex; |
|
|
// Add the subitems |
|
|
item.SubItems.Add(album.Title); |
|
|
bool hasPwd = (album.Password != null) |
|
|
&& (album.Password.Length > 0); |
|
|
item.SubItems.Add(hasPwd ? "y" : "n"); |
|
|
item.SubItems.Add(album.Count.ToString()); |
|
|
} |
|
|
|
3 |
When the album fails to load, |
else |
|
set the subitems to |
{ |
|
appropriate defaults. |
item.ImageIndex = MainForm.ErrorIndex; |
|
item.SubItems.Add(item.Text); |
|
|
|
|
|
|
item.SubItems.Add("?"); |
|
|
item.SubItems.Add("0"); |
|
|
} |
|
|
|
4 |
In either case, add the item |
listViewMain.Items.Add(item); |
|
to the list view. |
} |
|
|
} |
|
|
|
Compile and run your code to ensure that it works. When you look at the Details view, note how the width of each column can be adjusted by clicking on the vertical line between two columns and dragging it to the left or right.
Congratulations, you have just completed your first list view! Your life may never be the same. Before you go off and celebrate, there is one other topic related to columns that is worth some discussion.
14.3.3SORTING A COLUMN
It is typical in applications such as Windows Explorer to sort the contents of a List-
View control column whenever a column title is clicked. The first time the title is clicked, the items are sorted based on the column’s contents in ascending order, or a to z order for strings; and a second click sorts in descending, or z to a, order. Whether to support this behavior in your applications depends on the nature of the application and the user environment for which it is targeted. Many Windows users expect such behavior, and may find it odd if an application does not support this feature. In this section we look at how to support this feature in Windows Forms applications, using our MyAlbumExplorer application as an example.
458 |
CHAPTER 14 LIST VIEWS |
The ListView class provides three members of particular importance when you wish to support sorting in the Details view.
•The Sorting property defines how the items are initially sorted. This is a SortOrder enumeration value, one of None for no sorting, Ascending, or Descending. This defaults to None, which is why our application currently
displays the items in random order.
•The ColumnClick event occurs when a column is clicked. This is used to modify the control’s sorting behavior as appropriate for the selected column. Event handlers for this event receive a ColumnClickEventArgs parameter that contains a Column property indicating the column header clicked by the user.
•The ListViewItemSorter property defines the IComparer interface used to compare two ListViewItem objects for the list. An overview of the IComparer interface is given in .NET Table 14.6.
We will use each of these members to define the sorting behavior for our application. We will define a class supporting the IComparer interface first, and then use this class to implement a ColumnClick event handler.
.NET Table 14.6 IComparer interface
The IComparer interface is an interface for comparing two objects, and is part of the Systems.Collections namespace. This namespace also provides two implementations of this interface for comparing string objects. The Comparer class supports case-sensitive comparisons, while the CaseInsensitiveComparer class supports case-insensitive comparisons. Both of these classes provide a Default property that returns an initialized instance of the class.
|
Compare |
Returns an integer value indicating the equality |
|
|
relationship between two object instances. The |
Public Methods |
|
value returned is less than zero, zero, or greater |
|
than zero, corresponding to whether the first |
|
|
|
|
|
|
object is less than, equal to, or greater than the |
|
|
second, respectively. |
|
|
|
For a ListView object, the comparison interface must accept two ListViewItem objects and return an appropriate value depending on the current column and sorting order. The ListView object itself defines the current sorting order based on the Sorting property value. We will need to keep track of the current column as part of our IComparer implementation.
We will begin by implementing a comparison class within our MainForm definition. We will use the rather noncreative name MyListViewComparer for this class.
LISTVIEW COLUMNS |
459 |
To avoid hard-coding integer values into our code, the following steps also define constants for the column indices.
DEFINE A COMPARER CLASS FOR THE LIST VIEW
|
Action |
Result |
|
|
|
1 |
In the MainForm.cs source code |
private const int AlbumNameColumn = 0; |
|
window, define four constants for |
private const int AlbumTitleColumn = 1; |
|
each of the columns in our |
private const int AlbumPwdColumn = 2; |
|
private const int AlbumSizeColumn = 3; |
|
|
ListView control. |
|
|
|
|
|
|
|
2 |
Define the |
private class MyListViewComparer : IComparer |
|
MyListViewComparer class |
{ |
|
within the MainForm class |
// Associate a ListView with the class |
|
// Track the current sorting column |
|
|
definition. |
|
|
// Compare method implementation |
|
|
|
} |
|
|
|
3 |
Associate a ListView object |
// Associate a ListView with the class |
|
with this class via the |
private ListView _listView; |
|
constructor. |
public MyListViewComparer(ListView lv) |
|
|
|
|
|
{ |
|
|
_listView = lv; |
|
|
} |
|
|
|
4 |
Also define a ListView property |
public ListView ListView |
|
to retrieve this setting. |
{ |
|
|
get { return _listView; } |
|
|
} |
|
|
|
5 |
Allow the current sorting column |
// Track the current sorting column |
|
to be specified via a SortColumn |
private int _sortColumn = 0; |
|
property. |
public int SortColumn |
|
|
|
|
|
{ |
|
|
get { return _sortColumn; } |
|
|
set { _sortColumn = value; } |
|
|
} |
|
|
|
6 |
Define the Compare method |
// Compare method implementation |
|
required by the IComparer |
public int Compare(object a, object b) |
|
interface. |
{ |
|
|
|
|
|
|
7 |
In this method, convert the two |
// Throws exception if not list items |
|
objects into list view items. |
ListViewItem item1 = (ListViewItem)a; |
|
|
ListViewItem item2 = (ListViewItem)b; |
|
|
|
8 |
Swap the two items if the current |
// Account for current sorting order |
|
sorting order is descending. |
if (ListView.Sorting |
|
Note: We could handle the sort |
== SortOrder.Descending) |
|
{ |
|
|
order as part of each compari- |
ListViewItem tmp = item1; |
|
son, but swapping the items up |
item1 = item2; |
|
item2 = tmp; |
|
|
front seems easier. |
|
|
} |
|
|
|
|
460 |
CHAPTER 14 LIST VIEWS |
DEFINE A COMPARER CLASS FOR THE LIST VIEW (continued)
|
Action |
Result |
|
|
|
9 |
Handle the case where the |
// Handle nonDetails case |
|
current view is not Details. |
if (ListView.View != View.Details) |
|
Note: The comparer is called |
{ |
|
return CaseInsensitiveComparer.Default. |
|
|
whenever the items must be |
Compare(item1.Text, item2.Text); |
|
sorted, regardless of the current |
} |
|
|
|
|
view. |
|
|
Note how we use the default |
|
|
Comparer instance provided by |
|
|
the CaseInsensitiveCom- |
|
|
parer class. |
|
|
|
|
10 |
For the Details view, use a |
return CompareAlbums(item1, item2); |
|
separate method to compare the |
} |
|
two items. |
|
|
|
|
11 |
For the CompareAlbums method, |
public int CompareAlbums |
|
the following steps are required. |
(ListViewItem item1, ListViewItem item2) |
|
a. Find the subitem instances |
{ |
|
// Find the subitem instances |
|
|
corresponding to each item. |
ListViewItem.ListViewSubItem sub1 |
|
b. Return the appropriate result |
= item1.SubItems[SortColumn]; |
|
ListViewItem.ListViewSubItem sub2 |
|
|
based on the current column. |
= item2.SubItems[SortColumn]; |
|
|
// Return value is based on sort column |
|
|
switch (SortColumn) |
|
|
{ |
|
|
|
12 |
When one of the three string |
case MainForm.AlbumNameColumn: |
|
columns is selected, use the |
case MainForm.AlbumTitleColumn: |
|
default Comparer to compare the |
case MainForm.AlbumPwdColumn: |
|
{ |
|
|
two strings. |
|
|
return |
|
|
|
CaseInsensitiveComparer. |
|
|
Default.Compare( |
|
|
sub1.Text, sub2.Text); |
|
|
} |
|
|
|
13 |
When the Size column is |
case MainForm.AlbumSizeColumn: |
|
selected: |
{ |
|
a. Convert the strings to integer |
// Compare using integer values. |
|
int x1 = Convert.ToInt32(sub1.Text); |
|
|
values. |
int x2 = Convert.ToInt32(sub2.Text); |
|
b. Return the appropriate result. |
if (x1 < x2) |
|
Note: The ToInt32 method |
return -1; |
|
used here will throw an excep- |
else if (x1 == x2) |
|
return 0; |
|
|
tion if the given string cannot be |
|
|
else |
|
|
converted to an integer. |
return 1; |
|
|
} |
|
|
|
14 |
For any other column value, |
default: |
|
throw an exception indicating the |
throw new IndexOutOfRangeException( |
|
column was not recognized. |
"unrecognized column index"); |
|
} |
|
|
|
|
|
|
} |
|
|
|
LISTVIEW COLUMNS |
461 |