65.9K
CodeProject 正在变化。 阅读更多。
Home

扩展ListView

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.74/5 (50投票s)

2006年2月9日

4分钟阅读

viewsIcon

532846

downloadIcon

29482

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

Sample Image - EXListView.gif

引言

CodeProject 上有许多增强 ListView 功能的示例。我一直在寻找一种方法来显示和编辑子项上的多个图像,并能够按日期、数字、字符串和图像对 ListView 进行排序,但我找不到能够做到这一点的。子项还必须是可编辑的——无论是通过文本框还是用户定义的控件。最后,我想能够向子项添加控件,并提供某种“布尔”列。位于这种布尔列中的子项将能够显示两个值——真或假——可以用两个图像表示。如果将 Editable 属性设置为 true,用户可以单击这样的子项,值就会切换。

背景

以前,您必须使用 Win32 API 来完成上述操作。现在,随着 .NET Framework 2.0 的发布,使用所有者绘制(ownerdraw)的概念可以更容易地完成。如果 ListViewOwnerDraw 属性设置为 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()),您可以开始添加列。有三种不同类型的列:EXColumnHeaderEXEditableColumnHeader(其子项可以由默认的 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 日。
© . All rights reserved.