为 ListViewSortManager 添加多列排序






4.50/5 (3投票s)
轻松为 ListView 控件添加多列排序。
引言
很久以前(早在 2002 年),Eddie Velazquez 发布了一个小类,可以轻松地为 ListView
控件添加列排序。原始文章 在这里。
许多人(包括我)要求添加其他功能,特别是能够同时按多列排序。虽然他修复了一些 bug,但 Eddie 没有时间添加这个更重要的功能。有一天,我在一个项目中非常需要它,与其等待,不如我决定卷起袖子自己动手。
我一直想在这里发布它,让大家都能从中受益,但一直没有时间写这篇文章。但最终,它来了。
我添加到 Eddie 版本中最主要的功能是多列排序。但我还添加了
- 货币和 IP 地址排序。IP 排序器是从原始文章中 Eddie 的一个评论中获取的。
- 修复了
SortEnabled
属性的一个 bug ListViewBottomItem
类,用于始终位于底部的项目(例如,总计行)。
要同时按多列排序,请单击第一列,然后按住 Ctrl 键并单击其他列。
本文随附的演示项目是为 Visual Studio .NET 2003 和 .NET 1.1 编写的,因此可以覆盖更广泛的受众。我也在 Visual Studio 2005 和 .NET 2.0 中使用了这个类,一切都运行良好。
Using the Code
我试图让我的版本与 Eddie 的版本向后兼容,并且在 99% 的情况下都成功了。使用 ListViewSortManager
非常简单。您只需在构造函数中创建一个实例,设置列表视图和列排序器,即可完成。在下面的示例中,我已用粗体标出了必需的更改。
using Intelectix.Windows.Forms;
class MyForm()
{
ListView lstNames;
ListViewSortManager sortManager;
public MyForm()
{
InitializeComponent();
sortManager = new ListViewSortManager(lstNames, new Type[]
{
typeof(ListViewTextSort),
typeof(ListViewTextSort),
typeof(ListViewInt32Sort),
typeof(ListViewDateSort)
});
}
}
很简单,不是吗?如果您想为列表指定初始排序,请在构造函数的第三个参数中指定列索引,并在第四个参数中指定排序顺序。
sortManager = new ListViewSortManager(lstNames, new Type[]
{
typeof(ListViewTextSort),
typeof(ListViewTextSort),
typeof(ListViewInt32Sort),
typeof(ListViewDateSort)
}, 1, SortOrder.Descending); // Sort descending by second column
当然,您需要将 ListViewSortManager.cs 文件添加到您的项目中。
将项目添加到 ListView
如果您要将大量项目添加到 listview
中,请使用 ListView.Items.AddRange
或禁用 ListViewSortManager
。如果您逐个添加,列表视图将在每个项目后进行排序,您会注意到性能下降。
lstNames.BeginUpdate();
lstNames.Items.Clear();
sortManager.SortEnabled = false;
for(int i = 0; i < 1000; i++)
{
ListViewItem item = new ListViewItem();
.
.
.
lstNames.Items.Add(item);
}
sortManager.SortEnabled = true;
lstNames.EndUpdate();
创建自己的比较器
我提供了以下比较器:
- 文本 (
ListViewTextSort
) - 不区分大小写的文本 (
ListViewTextCaseInsensitiveSort
) - 日期 (
ListViewDateSort
) - 整数 (
ListViewInt32Sort
,ListViewInt64Sort
) - 双精度 (
ListViewDoubleSort
) - 货币 (
ListViewCurrencySort
) - 百分比 (
ListViewPercentSort
) - IP 地址 (
ListViewIPSort
)
如果您想对其他内容进行排序,实现自己的比较器非常简单(我使其比 Eddie 的版本更简单,但略有不同)。您只需要实现 IListViewSorter
接口,并比较两个项目。下面是 ListViewCurrencySort
的代码。
public class ListViewCurrencySort : IListViewSorter
{
public int Compare(String lhs, String rhs)
{
decimal result =
decimal.Parse(lhs, NumberStyles.Currency, CultureInfo.CurrentCulture) -
decimal.Parse(rhs, NumberStyles.Currency, CultureInfo.CurrentCulture);
if(result > 0)
return 1;
else if(result < 0)
return -1;
else
return 0;
}
}
其他改进
有一个 ListViewBottomItem
,在排序时,它始终位于最底部。这对于包含总计的行很有用。它的创建和使用方式与普通 ListViewItem
相同(尽管缺少一些构造函数)。
多列排序的工作原理
基本上,为了支持多列排序,ListViewSortManager
会维护一个已排序列索引的列表。
当用户单击一列时
- 如果未按 Control 键,
listView_ColumnClick
方法会检查同一列是否已在序列中的第一个位置,如果是,则仅切换顺序。否则,将清除整个排序列表,然后添加该列。 - 如果按住 Control 键,则单击的列将添加到排序序列的末尾。如果它之前在末尾,则会切换其排序顺序。如果它出现在序列中间的某个位置,则会从那里删除并添加到末尾。
序列包含列的索引,按它们应该排序的顺序排列。如果索引为负,则表示该列应按降序排序。
即将推出
我一直想添加的一项功能是设计器支持。我设想如下:
- 在设计器中,向您的窗体添加一个组件。
- 每个
listview
都有SortEnabled
、SortColumn
和SortOrder
属性,您可以进行设置。 - 在列设计器中,每列都有一个
Sorter
属性。
我只希望此部分标题中的“即将到来”尽快到来。:)
如果您有任何疑问、意见或改进建议,请随时使用下面的留言板,以便大家都能从中受益。