Winform下ListView实现排序功能
最近项目需要实现列表排序,由于是winform的,并使用了ListView列表控件,并且第一列显示了序号,要求:点击每列标题实现列表排序,并且序号列要跟随排序后的数据显示。
查看了微软的官方文档,ListView没有实现针对某列不参与排序的功能,在DataGridView中就有实现,考虑到更换控件可能付出的代价,决定还是继续用ListView实现,实现的思路大致如下:将ListView中的每一项转换成实体添加到List中,针对这个实体类实现Compare并继承ICompare接口,实现ListView的ColumnClick事件,在事件处理函数中获取点击的列名,并以此作为排序依据,主要代码如下:
private List<ListViewItemModel> _viewItemList = new List<ListViewItemModel>();//存储待排序实体
private ListViewColumnSorter lvwColumnSorter = new ListViewColumnSorter();//排序器
1 //列标题点击事件处理函数 2 private void LvTag_ColumnClick(object sender, ColumnClickEventArgs e) 3 { 4 if (e.Column == 0) return;//序号列不排序 5 _viewItemList.Clear();//清空存储ListViewItem列表 6 string colName = lvTag.Items[e.Column].SubItems[e.Column].Name;//取列名 7 foreach (ListViewItem item in lvTag.Items)//转换实体 8 { 9 ListViewItemModel model = item.ToModel<ListViewItemModel>(); 10 if (!_viewItemList.Contains(model)) 11 _viewItemList.Add(item.ToModel<ListViewItemModel>()); 12 } 13 lvTag.Items.Clear();//清空ListView 14 if (colName == lvwColumnSorter.SortColumnName)//检查点击的列是不是现在的排序列. 15 { 16 if (lvwColumnSorter.Order == SortOrder.Ascending)//重新设置此列的排序方法. 17 lvwColumnSorter.Order = SortOrder.Descending; 18 else 19 lvwColumnSorter.Order = SortOrder.Ascending; 20 } 21 else 22 { 23 lvwColumnSorter.SortColumnName = colName;//设置排序列,默认为正向排序 24 lvwColumnSorter.Order = SortOrder.Ascending; 25 } 26 _viewItemList.Sort(lvwColumnSorter); 27 this.lvTag.BeginUpdate(); 28 ListViewItem[] listViewItems = new ListViewItem[_viewItemList.Count]; 29 for (int i = 0; i < _viewItemList.Count; i++) 30 { 31 ListViewItemModel model = _viewItemList[i];//将实体转换为ListViewItem添加到ListView 32 ListViewItem item = new ListViewItem($"{i + 1}");//计算序号 33 item.Name = model.Epc;//设置Name 34 item.SubItems.Add(model.Epc).Name = "Epc"; 35 item.SubItems.Add(model.EpcLen.ToStr()).Name = "EpcLen"; 36 item.SubItems.Add(model.ReadCount.ToStr()).Name = "ReadCount"; 37 item.SubItems.Add(model.Rssi1.ToStr()).Name = "Rssi1"; 38 item.SubItems.Add(model.RssiAvg1.ToStr()).Name = "RssiAvg1"; 39 item.SubItems.Add(model.Rssi2.ToStr()).Name = "Rssi2"; 40 item.SubItems.Add(model.RssiAvg2.ToStr()).Name = "RssiAvg2"; 41 item.SubItems.Add(model.Rssi3.ToStr()).Name = "Rssi3"; 42 item.SubItems.Add(model.RssiAvg3.ToStr()).Name = "RssiAvg3"; 43 item.SubItems.Add(model.Rssi4.ToStr()).Name = "Rssi4"; 44 item.SubItems.Add(model.RssiAvg4.ToStr()).Name = "RssiAvg4"; 45 item.SubItems.Add(model.Tid).Name = "Tid"; 46 item.SubItems.Add(model.TidLen.ToStr()).Name = "TidLen"; 47 lvTag.Items.Add(item);//添加到列表 48 } 49 }
//ListViewColumnSorter 定义
public class ListViewColumnSorter : IComparer<ListViewItemModel>
{
private string _sortColumnName;// 指定按照哪个列排序
private CaseInsensitiveComparer _objectCompare;// 声明CaseInsensitiveComparer类对象,
public ListViewColumnSorter()
{
_sortColumnName = string.Empty;// 默认按第一列排序
Order = SortOrder.None;// 排序方式为不排序
_objectCompare = new CaseInsensitiveComparer();// 初始化CaseInsensitiveComparer类对象
}
public int Compare(ListViewItemModel x, ListViewItemModel y)
{
int compareResult;
Regex regex = new Regex(@"^\d+(\.\d+)?$");
PropertyInfo piX = x.GetType().GetProperty(_sortColumnName);
PropertyInfo piY = x.GetType().GetProperty(_sortColumnName);
if (regex.IsMatch(piX.GetValue(x).ToStr()) && regex.IsMatch(piY.GetValue(y).ToStr()))
compareResult = _objectCompare.Compare(Convert.ToDecimal(piX.GetValue(x)), Convert.ToDecimal(piY.GetValue(y)));
else
compareResult = _objectCompare.Compare(piX.GetValue(x), piY.GetValue(y));//比较
if (Order == SortOrder.Ascending)// 根据上面的比较结果返回正确的比较结果
return compareResult;// 因为是正序排序,所以直接返回结果
else if (Order == SortOrder.Descending)
return (-compareResult);// 如果是反序排序,所以要取负值再返回
else
return 0;// 如果相等返回0
}
public SortOrder Order { set; get; }//获取或设置排序方式
public string SortColumnName { get => _sortColumnName; set => _sortColumnName = value; }
}