Visual Studio .NET 2002.NET 1.0Windows 2003.NET 1.1Visual Studio 2010Windows 2000Windows XP中级开发Visual StudioWindows.NETC#
ListView 列排序器
一个列排序器,可以对包含字符串和数字(包括小数)的列进行排序,还可以对第一列按照图像然后按照字符串进行排序。
引言
很久以前我就开始使用 ListView
。过了一段时间,我急需一个列排序器。我只想对每一列进行排序。后来,我想也许也可以对图像进行排序。当然,在这种情况下,它应该先按图像排序,然后再按第一列中的文本排序。昨天我遇到了一个问题,一列包含字符串形式的数字。这又一次让我进入下一个版本,该版本应该确定字符串是否实际上是一个数字,然后按数字进行排序。我已经创建了一个示例项目,该项目为您利用了所有这些功能。请查看一下。
如何使用
如果您只想使用它,这非常简单。只需从页面顶部的链接下载源代码压缩包。在您的表单类中,只需声明
private ListViewColumnSorter lvwColumnSorter;
然后在表单的构造函数中,简单地添加
private void MyForm()
{
lvwColumnSorter = new ListViewColumnSorter();
this.listView1.ListViewItemSorter = lvwColumnSorter;
}
当然,现在您希望能够在单击列标题时进行排序。现在在 Visual Studio 中,选择您的 ListView
并转到属性,选择事件,然后双击ColumnClick。这将创建以下内容
this.listView1.ColumnClick +=
new System.Windows.Forms.ColumnClickEventHandler(this.listView1_ColumnClick);
这意味着,我们需要另一个方法来为我们控制排序
private void listView1_ColumnClick(object sender, System.Windows.Forms.ColumnClickEventArgs e)
{
ListView myListView = (ListView)sender;
// Determine if clicked column is already the column that is being sorted.
if ( e.Column == lvwColumnSorter.SortColumn )
{
// Reverse the current sort direction for this column.
if (lvwColumnSorter.Order == SortOrder.Ascending)
{
lvwColumnSorter.Order = SortOrder.Descending;
}
else
{
lvwColumnSorter.Order = SortOrder.Ascending;
}
}
else
{
// Set the column number that is to be sorted; default to ascending.
lvwColumnSorter.SortColumn = e.Column;
lvwColumnSorter.Order = SortOrder.Ascending;
}
// Perform the sort with these new sort options.
myListView.Sort();
}
现在您完成了...
代码基础
using System;
using System.Collections;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using System.Globalization;
namespace ListViewSorter
{
/// <summary>
/// This class is an implementation of the 'IComparer' interface.
/// </summary>
public class ListViewColumnSorter : IComparer
{
public enum SortModifiers
{
SortByImage,
SortByCheckbox,
SortByText
}
/// <summary>
/// Specifies the column to be sorted
/// </summary>
public int ColumnToSort;
/// <summary>
/// Specifies the order in which to sort (i.e. 'Ascending').
/// </summary>
public SortOrder OrderOfSort;
/// <summary>
/// Case insensitive comparer object
/// </summary>
private NumberCaseInsensitiveComparer ObjectCompare;
private ImageTextComparer FirstObjectCompare;
private CheckboxTextComparer FirstObjectCompare2;
private SortModifiers mySortModifier = SortModifiers.SortByText;
public SortModifiers _SortModifier
{
set
{
mySortModifier = value;
}
get
{
return mySortModifier;
}
}
/// <summary>
/// Class constructor. Initializes various elements
/// </summary>
public ListViewColumnSorter()
{
// Initialize the column to '0'
ColumnToSort = 0;
// Initialize the CaseInsensitiveComparer object
ObjectCompare = new NumberCaseInsensitiveComparer();
FirstObjectCompare = new ImageTextComparer();
FirstObjectCompare2 = new CheckboxTextComparer();
}
/// <summary>
/// This method is inherited from the IComparer interface. It compares the two objects passed using a case insensitive comparison.
/// </summary>
/// <param name="x">First object to be compared</param>
/// <param name="y">Second object to be compared</param>
/// <returns>The result of the comparison. "0" if equal, negative if 'x' is less than 'y' and positive if 'x' is greater than 'y'</returns>
public int Compare(object x, object y)
{
int compareResult = 0;
ListViewItem listviewX, listviewY;
// Cast the objects to be compared to ListViewItem objects
listviewX = (ListViewItem)x;
listviewY = (ListViewItem)y;
ListView listViewMain = listviewX.ListView;
// Calculate correct return value based on object comparison
if (listViewMain.Sorting != SortOrder.Ascending &&
listViewMain.Sorting != SortOrder.Descending)
{
// Return '0' to indicate they are equal
return compareResult;
}
if (mySortModifier.Equals(SortModifiers.SortByText) || ColumnToSort > 0)
{
// Compare the two items
if (listviewX.SubItems.Count <= ColumnToSort &&
listviewY.SubItems.Count <= ColumnToSort)
{
compareResult = ObjectCompare.Compare(null, null);
}
else if (listviewX.SubItems.Count <= ColumnToSort &&
listviewY.SubItems.Count > ColumnToSort)
{
compareResult = ObjectCompare.Compare(null, listviewY.SubItems[ColumnToSort].Text.Trim());
}
else if (listviewX.SubItems.Count > ColumnToSort && listviewY.SubItems.Count <= ColumnToSort)
{
compareResult = ObjectCompare.Compare(listviewX.SubItems[ColumnToSort].Text.Trim(), null);
}
else
{
compareResult = ObjectCompare.Compare(listviewX.SubItems[ColumnToSort].Text.Trim(), listviewY.SubItems[ColumnToSort].Text.Trim());
}
}
else
{
switch (mySortModifier)
{
case SortModifiers.SortByCheckbox:
compareResult = FirstObjectCompare2.Compare(x, y);
break;
case SortModifiers.SortByImage:
compareResult = FirstObjectCompare.Compare(x, y);
break;
default:
compareResult = FirstObjectCompare.Compare(x, y);
break;
}
}
// Calculate correct return value based on object comparison
if (OrderOfSort == SortOrder.Ascending)
{
// Ascending sort is selected, return normal result of compare operation
return compareResult;
}
else if (OrderOfSort == SortOrder.Descending)
{
// Descending sort is selected, return negative result of compare operation
return (-compareResult);
}
else
{
// Return '0' to indicate they are equal
return 0;
}
}
/// <summary>
/// Gets or sets the number of the column to which to apply the sorting operation (Defaults to '0').
/// </summary>
public int SortColumn
{
set
{
ColumnToSort = value;
}
get
{
return ColumnToSort;
}
}
/// <summary>
/// Gets or sets the order of sorting to apply (for example, 'Ascending' or 'Descending').
/// </summary>
public SortOrder Order
{
set
{
OrderOfSort = value;
}
get
{
return OrderOfSort;
}
}
}
public class ImageTextComparer : IComparer
{
//private CaseInsensitiveComparer ObjectCompare;
private NumberCaseInsensitiveComparer ObjectCompare;
public ImageTextComparer()
{
// Initialize the CaseInsensitiveComparer object
ObjectCompare = new NumberCaseInsensitiveComparer();
}
public int Compare(object x, object y)
{
//int compareResult;
int image1, image2;
ListViewItem listviewX, listviewY;
// Cast the objects to be compared to ListViewItem objects
listviewX = (ListViewItem)x;
image1 = listviewX.ImageIndex;
listviewY = (ListViewItem)y;
image2 = listviewY.ImageIndex;
if (image1 < image2)
{
return -1;
}
else if (image1 == image2)
{
return ObjectCompare.Compare(listviewX.Text.Trim(), listviewY.Text.Trim());
}
else
{
return 1;
}
}
}
public class CheckboxTextComparer : IComparer
{
private NumberCaseInsensitiveComparer ObjectCompare;
public CheckboxTextComparer()
{
// Initialize the CaseInsensitiveComparer object
ObjectCompare = new NumberCaseInsensitiveComparer();
}
public int Compare(object x, object y)
{
// Cast the objects to be compared to ListViewItem objects
ListViewItem listviewX = (ListViewItem)x;
ListViewItem listviewY = (ListViewItem)y;
if (listviewX.Checked && !listviewY.Checked)
{
return -1;
}
else if (listviewX.Checked.Equals(listviewY.Checked))
{
if (listviewX.ImageIndex < listviewY.ImageIndex)
{
return -1;
}
else if (listviewX.ImageIndex == listviewY.ImageIndex)
{
return ObjectCompare.Compare(listviewX.Text.Trim(), listviewY.Text.Trim());
}
else
{
return 1;
}
}
else
{
return 1;
}
}
}
public class NumberCaseInsensitiveComparer : CaseInsensitiveComparer
{
public NumberCaseInsensitiveComparer ()
{
}
public new int Compare(object x, object y)
{
if (x == null && y == null)
{
return 0;
}
else if (x == null && y != null)
{
return -1;
}
else if (x != null && y == null)
{
return 1;
}
if ((x is System.String) && IsDecimalNumber((string)x) && (y is System.String) && IsDecimalNumber((string)y))
{
try
{
decimal xx= Decimal.Parse(((string)x).Trim());
decimal yy= Decimal.Parse(((string)y).Trim());
return base.Compare(xx,yy);
}
catch
{
return -1;
}
}
else
{
return base.Compare(x,y);
}
}
// deprecated
//private bool IsWholeNumber(string strNumber)
//{
// Regex wholePattern = new Regex(@"^\d+$");
// return wholePattern.IsMatch(strNumber);
//}
private string GetNumberDecimalSeparator()
{
return System.Globalization.CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;
}
// http://stackoverflow.com/questions/4246077/matching-numbers-with-regular-expressions-only-digits-and-commas/4247184#4247184
// https://www.debuggex.com/r/Lyx0F0y1LORvNhwA
private bool IsDecimalNumber(string strNumber)
{
//@"^-?(\d+|(\d{1,3}((,|\.)\d{3})*))((,|\.)\d+)?$"
//string regex = @"^-?(?:(?:0|[1-9][0-9]*)(?:" + GetNumberDecimalSeparator() + @"[0-9]+)?|[1-9][0-9]{1,2}(?:,[0-9]{3})+)$";
string regex = @"^-?(\d+|(\d{1,3}((,|\.)\d{3})*))((,|\.)\d+)?$";
Regex wholePattern = new Regex(regex);
return wholePattern.IsMatch(strNumber);
}
}
}
历史
2003-11-04 - 已将“如何使用它”添加到描述中。
2013-08-16 - 添加了一些错误修复(数字排序、int64 排序、空子项)并添加了复选框排序
2015-07-21 - 添加了小数排序,修复了“SortOrder”与其他类冲突的可能命名空间错误