** 使用 Windows Form 按列排序 ListView 项目 **
** 摘要: ** 说明如何根据所单击的列在 Microsoft .NET 中的 ListView 控件提供项目排序。
** 简介 **
** ListView ** 控件是显示文件系统信息和显示 XML 或数据库数据的非常好的方式。 ListView 控件通常用于显示表示项目以及项目文本的图形图标。此外, ListView 控件还可以用于显示有关子项目中项目的其他信息。例如,如果 ListView 控件显示一列文件,您可以配置 ListView 控件来显示作为子项目的诸如文件大小和属性的详细信息。要显示 ListView 控件中的子项目信息,必须将 View 属性设置为 View.Details 。此外,您必须创建 ColumnHeader 对象并将这些对象分配给 ListView 控件的 Columns 属性。在设置这些属性后,项目以行和列格式进行显示,类似于 DataGrid 控件。以这种方式显示项目的能力使 ListView 控件为从任意类型的数据源显示数据提供了快速、简便的解决方案。
对 ** ListView ** 控件进行排序是通过使用 ListView 的 Sorting 属性而提供的。这使您可以定义要应用到项目的排序类型。如果您只想按项目排序,这是一个非常好的功能。如果您要按子项目排序,必须使用 ListView 控件的自定义排序功能。本文将说明如何在 ListView 控件中执行自定义排序,以及在排序时如何处理特殊的数据类型条件。
** ListView 控件的自定义排序功能 **
** ListView ** 控件提供了您可以使用排序的功能,而不是由 Sorting 属性提供。当 ListView 控件使用 Sorting 属性排序项目时,它使用一个实现 System.Collections.IComparer 接口的类。这个类提供用于排序每个项目的排序功能。为了按子项目进行排序,您必须创建自己的类,来实现反过来可以实现 ListView 控件所需排序的 IComparer 接口。该类利用构造函数进行定义,该构造函数可以指定 ListView 控件排序所用的列。在您创建这个类后(通常将其作为窗体的嵌套类),您可以创建该类的一个实例,并将其分配到 ListView 的 ListViewItemSorter 属性。当调用 Sort 方法时,这会确定 ListView 控件将要使用的自定义排序类。 Sort 方法执行 ListView 项目的实际排序。
升序排序
以下部分提供的基本示例说明了在 ** ListView ** 控件中基于其子项目的排序。该示例说明了以升序排序 ListView 控件中的项目。升序排序或降序排序将会在本文的稍后部分进行说明。此处的目标就是说明在 ListView 控件中进行自定义排序的基本要求。
** 初始化控件 **
如果要开始,请创建 ** ListView ** 控件的实例,并将其添加到窗体中。在控件位于窗体上后,使用 Items 属性将项目添加到 ListView 控件。您可以添加任意多的项目,只要确保每个项目的文本都是唯一的。在您创建项目时,为每个项目添加两个子项目。第一个子项目应该包含数字信息,第二个子项目包含日期信息。下面的表格示例说明该信息在 ListView 控件中可能如何显示。
项目
|
子项目 1
|
子项目 2
---|---|---
Alpha
|
1.0
|
4/5/1945
Charlie
|
3.5
|
1/9/1920
Bravo
|
2.4
|
12/8/1930
创建两个 ** ColumnHeader ** 对象,并将它们分配到 ListView 控件的 Columns 属性中。将 View 属性设置为 View.Details 。
** 处理 ColumnClick 事件 **
为了确定按哪个子项目集进行排序,您需要了解用户何时单击某个子项目的列标题。为此,您需要为 ** ListView ** 的 ColumnClick 事件创建一个事件处理方法。将事件处理方法作为窗体中的一个成员,并确保它包含的签名相似于下面代码示例所显示的签名。
'Visual Basic
Private Sub listView1_ColumnClick(sender As Object, e As System.Windows.Forms.ColumnClickEventArgs)
End Sub
//C#
private void listView1_ColumnClick(object sender, System.Windows.Forms.ColumnClickEventArgs e)
{
}
通过向窗体的构造函数中添加代码,将事件处理方法连接到 ** ListView ** 控件,如下面的示例所示。
'Visual Basic
AddHandler listView1.ColumnClick, AddressOf Me.listView1_ColumnClick
//C#
this.listView1.ColumnClick += new System.Windows.Forms.ColumnClickEventHandler(this.listView1_ColumnClick);
将下面的代码添加到用于 ** ColumnClick ** 事件的事件处理方法。
'Visual Basic
' Set the ListViewItemSorter property to a new ListViewItemComparer
' object.
Me.listView1.ListViewItemSorter = New ListViewItemComparer(e.Column)
' Call the sort method to manually sort.
listView1.Sort()
//C#
// Set the ListViewItemSorter property to a new ListViewItemComparer
// object.
this.listView1.ListViewItemSorter = new ListViewItemComparer(e.Column);
// Call the sort method to manually sort.
listView1.Sort();
添加到事件处理方法的代码会利用 ** ListViewItemComparer ** 类(在下一部分中定义)的新实例来设置 ListView 控件的 ListViewItemSorter 属性,然后分配要单击的列。被单击的列作为事件参数的组成部分进行传递。在设置 ListViewItemSorter 属性后,调用 Sort 方法来执行手动排序。
** 创建 ListViewItemComparer 类 **
正如前面提到的那样,在 ** ListView ** 控件中进行自定义排序的关键在于创建实现 System.Collections.IComparer 接口的类。就是这个类为项目提供排序。对于这个示例,定义了名为 ListViewItemComparer 的类,并且将其添加为窗体的嵌套类。ListViewItemComparer 执行传递到其构造函数的指定列的基本升序排序。将以下类定义添加到 Form 类并确保它在窗体内是正确嵌套的。
'Visual Basic
' Implements the manual sorting of items by column.
Class ListViewItemComparer
Implements IComparer
Private col As Integer
Public Sub New()
col = 0
End Sub
Public Sub New(column As Integer)
col = column
End Sub
Public Function Compare(x As Object, y As Object) As Integer _
Implements System.Collections.IComparer.Compare
Dim returnVal as Integer = -1
returnVal = [String].Compare(CType(x, _
ListViewItem).SubItems(col).Text, _
CType(y, ListViewItem).SubItems(col).Text)
Return returnVal
End Function
End Class
//C#
// Implements the manual sorting of items by column.
class ListViewItemComparer : IComparer {
private int col;
public ListViewItemComparer() {
col=0;
}
public ListViewItemComparer(int column)
{
col=column;
}
public int Compare(object x, object y)
{
int returnVal = -1;
returnVal = String.Compare(((ListViewItem)x).SubItems[col].Text,
((ListViewItem)y).SubItems[col].Text);
return returnVal;
}
}
以一个名为 ** Compare ** 的 IComparer 接口的必要方法执行排序。这个方法将两个对象作为参数,而参数会包含要进行比较的两个项目。当在 ListView 控件的 ColumnClick 事件处理方法中调用 Sort 方法时, Sort 方法会使用已定义并已分配到 ListViewItemSorter 属性的 ListViewItemComparer 对象,并且调用其 Compare 方法。创建 ListViewItemComparer 对象后,分配给它被单击的列的索引。该列的索引用于从需要进行排序的列中访问子项目。然后,将子项目传递到 String.Compare 方法,该方法比较项目并返回三个结果中的一个。如果 x 参数中的项目小于 y 参数中的项目,则返回一个小于零的值。如果两个项目相同,则返回零。最后,如果 x 参数中的值大于 y 参数中的值,则返回一个大于零的值。 Compare 方法返回的值传递回 Sort 方法,这确定正在比较的每个项目在列中的位置。 Sort 方法可以根据在所选择列中排序所有子项目的需要对 Compare 方法调用任意多次。
前面的示例就完成了。如果您运行该示例并单击 ** ListView ** 控件的列标题,项目将会按字母顺序或数字顺序进行适当地排序。唯一不能正确排序的列就是包含日期信息的列。稍后本文将介绍排序日期列。
这个示例说明了在 ** ListView ** 控件中执行基本手动项目排序所需要的基本要素。接下来的部分会扩展这个示例,提供升序和降序排序功能。
升序或降序排序
** ListView ** 控件的用户将期望具有同时以升序和降序排序项目的功能。为了实现这个功能,需要对前面的示例进行某些改动,以便使 Compare 方法可以确定要排序的项目。
** 对窗体的更改 **
通常情况下,要在升序和降序排序之间切换,您要多次单击列标题。用户期望如果他们单击列标题,排序将会发生,随后再次单击将更改排序顺序。前面的代码示例需要能够确定何时多次单击列。为此,您可以将一个私有整数变量添加到 ** Form ** 类。这个变量存储上一次单击的列。 ColumnClick 事件处理方法将使用这个变量来比较上一次的列与当前单击的列,并确定它们是否相同。将以下成员定义添加到 Form 类中。
'Visual Basic
Dim sortColumn as Integer = -1
//C#
private int sortColumn = -1;
** ColumnClick 事件处理方法的更改 **
在前面的示例中定义的 ** ColumnClick ** 事件处理方法需要进行修改,以便跟踪单击过的列和当前排序顺序。添加以下代码以替换在前面的示例中创建的 ColumnClick 事件处理方法中的代码。
'Visual Basic
Private Sub listView1_ColumnClick(sender As Object, e As
System.Windows.Forms.ColumnClickEventArgs)
' Determine whether the column is the same as the last column clicked.
If e.Column <> sortColumn Then
' Set the sort column to the new column.
sortColumn = e.Column
' Set the sort order to ascending by default.
listView1.Sorting = SortOrder.Ascending
Else
' Determine what the last sort order was and change it.
If listView1.Sorting = SortOrder.Ascending Then
listView1.Sorting = SortOrder.Descending
Else
listView1.Sorting = SortOrder.Ascending
End If
End If
' Call the sort method to manually sort.
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow