关于ListView排序的众多问题

 

最近需要在软件中增加FTP功能,说是简单的功能,但是做起来也遇到了不少问题。主要问题就是目录浏览的问题,如何从FTP返回的列表中分割出大小、修改时间等也是当初没有想到的。而在列表展示上使用ListView控件的主要原因就是ListView控件"添加"数据比较自然,而DataGridView更多的是"绑定"数据。
随后发现ListView没有排序功能。
其实排序功能还是有的,只不过需要自己给定一个比较器。

listView1.ListViewItemSorter = XXXComparer.Instance(XXXComparer : IComparer)

这就是我FTP的窗口。只显示了文件名、大小和修改时间,文件名中目录使用[目录名]的方式展示,文件名的排序方式按道理上来讲应该是向上、目录、文件这种顺序。大小和修改时间就不用多说了。
这时候,问题就出来了:ListView的项(SubItem)没有数据类型一说。
对此,给我ListViewSubItem增加了一个强类型的ListViewSubItem:

/// <summary>
/// 强类型ListViewSubItem
/// </summary>
/// <typeparam name="T"></typeparam>
public class ListViewTypeSubItem<T> : ListViewItem.ListViewSubItem
{
    public ListViewTypeSubItem()
    {
        ValueType = typeof(T);
    }

    public Type ValueType { get; set; }

    public T Value { get; set; }
}

当然,这个所谓的强类型还是有一定的问题。暂时这么着吧。
有了强类型的 ListViewSubItem 那么给ListView赋值就要有相应的修改。

foreach (var file in files)
{
    lvi = new ListViewItem(file.IsDirectory ? string.Format("[{0}]", file.Name) : file.Name);

    size = new ListViewTypeSubItem<long>();
    size.Text = file.Size.ToString("N0");
    size.Value = file.Size;
    lvi.SubItems.Add(size);

    date = new ListViewTypeSubItem<DateTime>();
    date.Text = file.CreateTime.ToString("yyyy-MM-dd HH:mm");
    date.Value = file.CreateTime;
    lvi.SubItems.Add(date);

    lvi.Tag = file.IsDirectory ? FileTypeEnum.Directory : FileTypeEnum.File;

    lvFtpFile.Items.Add(lvi);
}

当然,重要的比较器还没有写。这里列出我写的比较器,其中应该有点问题,因为当初没有想让他能点两次。也就是说没有想让他支持点一次是asc,再点一次就是desc。本来只是想做个排序,让大小和修改时间逆序排,而文件名就按我上面说的规则排列。最后需求有所变动。
说了半天,列出我的比较器:

/// <summary>
/// ListViewItem自定义排序
/// 对long类型和DateTime类型进行处理(DESC)
/// 对于字符串,目录排在文件上面,向上排在最上边
/// </summary>
public class ListViewItemComparer : IComparer
{
    private static int col;
    private static bool isDesc = false;

    public ListViewItemComparer(int column)
    {
        col = column;
    }

    public int Compare(object x, object y)
    {
        int result = 0;
        var sub = ((ListViewItem)x).SubItems[col];
        if (sub is ListViewTypeSubItem<long>)
        {
            var sub_x = ((ListViewItem)x).SubItems[col] as ListViewTypeSubItem<long>;
            var sub_y = ((ListViewItem)y).SubItems[col] as ListViewTypeSubItem<long>;
            if (sub_x.Value > sub_y.Value)
            {
                result = 1;
            }
            else if (sub_x.Value == sub_y.Value)
            {
                result = 0;
            }
            else
            {
                result = -1;
            }
        }
        else if (sub is ListViewTypeSubItem<DateTime>)
        {
            var sub_x = ((ListViewItem)x).SubItems[col] as ListViewTypeSubItem<DateTime>;
            var sub_y = ((ListViewItem)y).SubItems[col] as ListViewTypeSubItem<DateTime>;

            result = DateTime.Compare(sub_y.Value, sub_x.Value);
        }
        else
        {
            string sub_x = ((ListViewItem)x).SubItems[col].Text;
            string sub_y = ((ListViewItem)y).SubItems[col].Text;
            if ((sub_x[0] == '[' && sub_x[sub_x.Length - 1] == ']') &&
            (sub_y[0] != '[' || sub_y[sub_y.Length - 1] != ']'))
            {
                return -1;
            }
            else
            {
                result = string.Compare(sub_x, sub_y);
            }
        }

        var lvi_x = (ListViewItem)x;
        var lvi_y = (ListViewItem)y;

        if (lvi_x.Text == "[..]")
        {
            return -1;
        }

        //if (lvi_y.Text == "[..]")
        //{
        //   return isDesc ? 1 : -1;
        //}

        return isDesc ? result : result == 0 ? 0 : result == 1 ? -1 : 1;
    }

    public static ListViewItemComparer Sort(int column = 0)
    {
        isDesc = !isDesc;

        return new ListViewItemComparer(column);
    }
}

应该从代码中更能感觉到曾经改过的样子。
自我感觉上面的

return isDesc ? result : result == 0 ? 0 : result == 1 ? -1 : 1;

一定会有人说。哈哈。

我的博客原文地址:关于ListView排序的众多问题

欢迎来我的博客:nanqi.info

原文地址:https://www.cnblogs.com/nanqi/p/ListViewSort.html