Basic ListView
The ListView control is most often used for a multicolumn list of items. It actually supports four distinct modes that you have probably already seen in Windows Explorer. You specify the mode by setting the ListView.View property to one of the values from the View enumeration.
LargeIcon, which displays full-sized (32 × 32 pixel) icons with a title beneath each one. Items are displayed from left to right, and then on subsequent lines.
SmallIcon, which displays small (16 × 16 pixel) icons with descriptive text at the right. Items are displayed from left to right, and then on subsequent lines.
List, which displays small icons with descriptive text at the right. It's the same as SmallIcon, except it fills items from top to bottom, and then in additional columns. The scrollbar (if needed) is horizontal.
Details, which displays the familiar multicolumn layout. Each item appears on a separate line, and the leftmost column contains a small icon and label. Column headers identify each column, and allow user resizing (and sorting, if the application supports it). The Details view is the only view that supports showing more than an icon and one piece of information per item.
Tip
In Visual Studio.NET, the ListView control uses a designer that allows you to add items and subitems. To use it, just click the ellipses (…) next to the Items property in the Property Window. It's quite impressive, but I won't discuss it in this chapter, as pure code gives a clearer understanding of the issues involved.To understand the different styles of ListView, it helps to create a simple example. First, create a ListView and two ImageList controls, one to hold any required small icons and one to hold large icons. You can associate the ListView with the corresponding ImageList like this:
listAuthors.SmallImageList = imagesSmall;
listAuthors.LargeImageList = imagesLarge;
Once the ImageList is associated, images can be assigned to individual list items by setting a convenient ImageIndex property. You can change the ImageIndex at any time to indicate an item that has changed status.
What follows is the code needed to load information into a ListView, in response to a button click. This example relies on a GetProducts() method that returns a DataTable (either by querying a database or by constructing it manually). I won't talk about the ADO.NET code you might use to create this DataTable (as this is better served by a dedicated book about databases and .NET), although you can look at the online code for this chapter to see the details. As with most of the examples I use, the data is retrieved from an XML file, which guarantees that you can use the examples even if you don't have a relational database product handy.
private void cmdFillList_Click(object sender, System.EventArgs e)
{
// Fill a DataTable using a helper class (not shown).
DataTable dt = StoreDB.GetProducts();
foreach (DataRow dr in dt.Rows)
{
// Create the item, with the text from the ModelName field.
ListViewItem listItem = new ListViewItem(dr["ModelName"].ToString());
// Give every item the same picture.
listItem.ImageIndex = 0;
// Add the item to the ListView.
listAuthors.Items.Add(listItem);
}
}
This is ListView code is at its simplest. ListViewItem objects are created, and added to the list. The ListViewItem constructor allows you to specify the default item text (the Text property) and the ImageIndex points to the first picture in the collection. Note that the ImageIndex applies to both the SmallImageList and LargeImageList, meaning that your ImageList objects must use the exact same ordering. The appropriate picture is chosen based on the view style.
Finally, to make the code a little more interesting, a group of radio buttons allows the user to switch between the different view styles. Rather than scatter the code for this in multiple procedures, use a single method that retrieves a tag value:
private void NewView(object sender, System.EventArgs e)
{
// Set the current view mode based on the number in the tag value of the
// selected radio button.
listAuthors.View = (View)(((Control)sender).Tag);
// Display the current view style.
this.Text = "Using View: " + listAuthors.View.ToString();
}
The tag values can be set at design time or in code when the form is first loaded:
optLargeIcon.Tag = View.LargeIcon;
optSmallIcon.Tag = View.SmallIcon;
optDetails.Tag = View.Details;
optList.Tag = View.List;
The NewView() method is attached to the CheckedChanged control event for all four option buttons in the form's initialization code:
this.optList.CheckedChanged += new System.EventHandler(this.NewView);
this.optDetails.CheckedChanged += new System.EventHandler(this.NewView);
this.optSmallIcon.CheckedChanged += new System.EventHandler(this.NewView);
this.optLargeIcon.CheckedChanged += new System.EventHandler(this.NewView);
If you try this application, you'll see that it doesn't appear to work in details view. The reason is that the ListView only displays information in details view if you have added the appropriate column headers. The example below rewrites the ListView code to fill multiple columns of information. Note, however, that this extra information is ignored in other view styles.
private void cmdFillList_Click(object sender, System.EventArgs e)
{
DataTable dt = StoreDB.GetProducts();
// Suspending automatic refreshes as items are added/removed.
listAuthors.BeginUpdate();
foreach (DataRow dr in dt.Rows)
{
ListViewItem listItem = new ListViewItem(dr["ModelName"].ToString());
listItem.ImageIndex = 0;
// Add sub-items for Details view.
listItem.SubItems.Add(dr["ProductID"].ToString());
listItem.SubItems.Add(dr["Description"].ToString());
listAuthors.Items.Add(listItem);
}
// Add column headers for Details view.
listAuthors.Columns.Add("Product", 100, HorizontalAlignment.Left);
listAuthors.Columns.Add("ID", 100, HorizontalAlignment.Left);
listAuthors.Columns.Add("Description", 100, HorizontalAlignment.Left);
// Re-enable the display.
listAuthors.EndUpdate();
}
When adding a ColumnHeader, you have the chance to specify a width in pixels, a title, and the alignment for values in the column. Figure 6-4 shows the four different view styles. This test program is included with the chapter code with the project name ListViewExample.
Figure 6-4: Different view styles with the ListView control
The ListView is different from almost any other grid control in that it designates every column except the first one as a subitem. This idiosyncrasy shouldn't trouble you too much, but note that it causes the column header indexes to differ from the subitem indexes. For example, listItem.SubItems.Items(0) is the first subitem while the corresponding column is listAuthors.Columns.Items(1).
Tip
The previous example uses a ListView for its most common task: representing items. However, ListView controls can also represent actions. For example, consider the Control panel, that uses a ListView in LargeIcon view to provide access to a number of different features. Remember, different view styles suggest different uses (and in the case of the Details view, show different information), so you should not allow the user to change the style through a setting in your application. Instead, choose the most suitable style when creating the control.
Table 6-2: Basic ListView Members
MemberDescription
ColumnsHolds the collection of ColumnHeader objects used in Details view.
FocusedItem, SelectedItem, and SelectedIndicesAllows you to retrieve the item that currently has focus or the currently selected items (the user can select multiple icons by dragging a box around them or by holding down the Ctrl key). You can also examine the Focused and Selected properties of each ListViewItem.
ItemsHolds the collection ListViewItem objects displayed in the ListView.
LargeImageList and SmallImageListReferences the ImageList control that is used for large and small icons. The individual icons are identified by the ListViewItem.ImageIndex property.
MultiSelectWhen set to false, prevents a user from selecting more than one item at a time.
ViewSets the ListView style using the View enumeration.
SelectedItemIndexChanged eventOccurs whenever the user selects an item, except when the same item is selected twice in a row.