最近需要在软件中增加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