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

为 ListViewSortManager 添加多列排序

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.50/5 (3投票s)

2007 年 12 月 1 日

CPOL

4分钟阅读

viewsIcon

62410

downloadIcon

1196

轻松为 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 属性。

我只希望此部分标题中的“即将到来”尽快到来。:)

如果您有任何疑问、意见或改进建议,请随时使用下面的留言板,以便大家都能从中受益。

© . All rights reserved.