扩展ListView






4.74/5 (50投票s)
2006年2月9日
4分钟阅读

532846

29482
一个扩展的 ListView 控件,它可以显示子项上的多个图像,允许用户使用用户定义的控件(也是图像子项)编辑子项,包含布尔子项,并且可以通过日期、数字、字符串和图像对列进行排序。

引言
CodeProject 上有许多增强 ListView 功能的示例。我一直在寻找一种方法来显示和编辑子项上的多个图像,并能够按日期、数字、字符串和图像对 ListView 进行排序,但我找不到能够做到这一点的。子项还必须是可编辑的——无论是通过文本框还是用户定义的控件。最后,我想能够向子项添加控件,并提供某种“布尔”列。位于这种布尔列中的子项将能够显示两个值——真或假——可以用两个图像表示。如果将 Editable 属性设置为 true,用户可以单击这样的子项,值就会切换。
背景
以前,您必须使用 Win32 API 来完成上述操作。现在,随着 .NET Framework 2.0 的发布,使用所有者绘制(ownerdraw)的概念可以更容易地完成。如果 ListView 的 OwnerDraw 属性设置为 false,您可以自己完成 ListView 的所有绘制。在这个 EXListView 类中,我广泛使用了所有者绘制。尽管使用 Win32 API 比使用 .NET Framework 的所有者绘制要快,但这个 ListView 仍然很快,即使有 1000 个包含多个图像的子项的项。
使用代码
本文附带的代码是 EXListView 类、EXComboBox 类以及一个使用这些控件的简单窗体。我添加了一个可执行文件,但您可以使用命令 csc /t:winexe /r:System.Windows.Forms.dll EXListView.cs EXComboBox.cs MyForms.cs 轻松自行编译——编译器 csc.exe 可以在 Windows XP 的 C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\ 中找到。
定义实例并添加列
如果您已经创建了 EXListView 类的实例(例如:EXListView exlstv = new EXListView()),您可以开始添加列。有三种不同类型的列:EXColumnHeader、EXEditableColumnHeader(其子项可以由默认的 TextBox 或用户定义的控件编辑),以及 EXBoolColumnHeader(其子项只能显示真或假,并且可以选择性地进行编辑)。
例如,要获得一个可以由默认 TextBox 编辑的列标题,请执行以下操作:
EXEditableColumnHeader editcol = 
                  new EXEditableColumnHeader("Movie");
如果您想指定一个控件来编辑子项,请执行以下操作:
// define a control to edit the subitems of this column
ComboBox cmbx = new ComboBox();
cmbx.Items.AddRange(new string[] {"1", "2", "3", "4"});
// define a columnheader whose subitems can be edited
EXEditableColumnHeader editcol = 
     new EXEditableColumnHeader("Position");
// add the combobox to the column
editcol.MyControl = cmbx;
一个布尔列
EXBoolColumnHeader boolcol = new EXBoolColumnHeader("OK");
// if you want the users to be able to edit
// the boolean values, set the Editable property to true
boolcol.Editable = true;
// specify an image for each of the values
boolcol.TrueImage = Image.FromFile("true.png");
boolcol.FalseImage = Image.FromFile("false.png");
向 EXListView 添加(子)项
一个常规的 ListViewItem
EXListViewItem lstvitem = new EXListViewItem("Pete");
可以显示图像的项和子项有一个 MyValue 属性,该属性可以保存(子)项的实际文本值。如果您不想显示文本,但需要某种值(例如,插入数据库),这将非常有用。
一个只能显示一张图像的项
EXImageListViewItem imglstvitem = new EXImageListViewItem();
imglstvitem.MyImage = Image.FromFile("Pete.jpg");
imglstvitem.MyValue = "Pete";
一个可以显示多个图像的项
EXMultipleImagesListViewItem mimglstvitem = 
        new EXMultipleImagesListViewItem();
// define arraylist with all the images
ArrayList images = new ArrayList(new object[] 
          {Image.FromFile("Pete.jpg"), 
          Image.FromFile("man.png")});
mimglstvitem.MyImages = images;
imglstvitem.MyValue = "Pete the man";
同样,您可以将子项添加到 EXListView。有关更多信息,请参阅 EXListView 类。
使用 EXComboBox 编辑带图像的项
源代码还包含一个扩展的 ComboBox 类——EXComboBox 类:这是一个可以包含图像的组合框。您可以使用此组合框来编辑 EXListView 中带图像的(子)项。
// create an EXListView
EXListView lstv = new EXListView();
// craete an EXComboBox
EXComboBox excmbx = new EXComboBox();
excmbx.MyHighlightBrush = Brushes.Goldenrod;
excmbx.ItemHeight = 20;
// add images to the combobox and the values
excmbx.Items.Add(new EXComboBox.EXImageItem(
       Image.FromFile("music.png"), "Music"));
excmbx.Items.Add(new EXComboBox.EXImageItem(
     Image.FromFile("comedy.png"), "Comedy"));
excmbx.Items.Add(new EXComboBox.EXMultipleImagesItem(
       new ArrayList(new object[] 
       {Image.FromFile("love.png"), 
       Image.FromFile("comedy.png")}), 
       "Romantic comedy"));
// add this combobox to the first columnheader
lstv.Columns.Add(new EXEditableColumnHeader("Genre", 
                                       excmbx, 60));
运行时添加和删除图像
如果您想在运行时添加或删除图像,只需将 MyImage 属性设置为 null,或者,对于多图像(子)项,可以使用 ArrayList 方法,如 Add() 和 RemoveAt()。示例
如果您想从第三行的第二个(第二列)EXMulitpleImagesListViewSubItem 中删除第二个图像,请执行以下操作:
EXMultipleImagesListViewSubItem subitem = 
   lstv.Items[2].SubItems[1] 
   as EXMultipleImagesListViewSubItem;
subitem.MyImages.RemoveAt(1);
lstv.Invalidate(subitem.Bounds);
您必须自行使此矩形无效。
调整行高
由于所有绘制都在所有者绘制事件中完成,因此 SmallImageList 属性仅用于在列标题中显示向上和向下的箭头,而不用于在 ListViewItem 中显示图像。要调整行高,您需要分配一个 ImageList 并将 Size 设置为适当的大小。这是一个粗糙的解决方法,但这是我唯一能找到的方法。如果您能找到其他方法,请告诉我。
添加控件
要将控件添加到子项,请创建一个 EXControlListViewSubItem,然后创建控件,将 EXControlListViewSubItem 添加到 listviewitem,最后使用 EXListView 方法 AddControlToSubitem 将控件添加到 EXControlListViewSubItem。
EXListViewItem item = new EXListViewItem("Item 1");
EXControlListViewSubItem cs = new EXControlListViewSubItem();
ProgressBar b = new ProgressBar();
b.Minimum = 0;
b.Maximum = 1000;
b.Step = 1;
item.SubItems.Add(cs);
lstv.AddControlToSubItem(b, cs);
关注点
目前 EXListView 类中存在一个恼人的错误:当您的鼠标指针从左到右移入 ListView 时,DrawItem 事件将被触发,但伴随着 DrawSubItem 事件。因此,ListViewItem 将被重绘,但子项不会。如果 ListViewItem 的内容(由第一个子项表示)大于列的宽度,则内容会覆盖相邻的子项。
历史
- 创建于 2006 年 2 月 9 日。
- 更新了代码和文章:现在您还可以使用图像编辑列 - 2006 年 2 月 15 日。
