扩展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 日。