为 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属性。
我只希望此部分标题中的“即将到来”尽快到来。:)
如果您有任何疑问、意见或改进建议,请随时使用下面的留言板,以便大家都能从中受益。


