按列对ListView排序

目前我在listview上使用自定义排序器,每次单击FIRST列时我都可以对listview进行排序,但不会按其他列排序。

SortStyle:变量以确定它是Ascending Sort还是Descending。

if (e.Column == 0) { if (SortStyle == 0) { List.ListViewItemSorter = customSortDsc; SortStyle = 1; } else { List.ListViewItemSorter = customSortAsc; SortStyle = 0; } } 

在为第一列排序时,这可以正常工作,但如果您要在任何其他列上执行此操作,则只需按第一列排序。 有没有办法按列点击排序?

如果您开始使用ListView,请自己做一个大忙,并使用ObjectListView 。 ObjectListView是.NET WinForms ListView的开源包装器,它使ListView更易于使用,并为您解决了许多常见问题。 按列排序是自动处理的众多内容之一。

说真的,你永远不会后悔使用ObjectListView而不是普通的ListView。

忘记你的自定义分拣机。 重新开始使用下一页的代码。 它将向您展示如何定义从IComparer接口inheritance的类。 每行都已注释掉,因此您可以实际查看正在发生的事情。 唯一可能的复杂因素是如何从Listview控件中检索Listview项。 得到那些平方,你需要做的就是复制并粘贴IComparer接口类和columnClick方法。

http://support.microsoft.com/kb/319401

我使用列名来排序,根据存储在列中的数据类型设置可能需要处理的任何排序细节,或者如果列已经排序(asc / desc)。 这是我的ColumnClick事件处理程序的片段。

 private void listView_ColumnClick(object sender, ColumnClickEventArgs e) { ListViewItemComparer sorter = GetListViewSorter(e.Column); listView.ListViewItemSorter = sorter; listView.Sort(); } private ListViewItemComparer GetListViewSorter(int columnIndex) { ListViewItemComparer sorter = (ListViewItemComparer)listView.ListViewItemSorter; if (sorter == null) { sorter = new ListViewItemComparer(); } sorter.ColumnIndex = columnIndex; string columnName = packagedEstimateListView.Columns[columnIndex].Name; switch (columnName) { case ApplicationModel.DisplayColumns.DateCreated: case ApplicationModel.DisplayColumns.DateUpdated: sorter.ColumnType = ColumnDataType.DateTime; break; case ApplicationModel.DisplayColumns.NetTotal: case ApplicationModel.DisplayColumns.GrossTotal: sorter.ColumnType = ColumnDataType.Decimal; break; default: sorter.ColumnType = ColumnDataType.String; break; } if (sorter.SortDirection == SortOrder.Ascending) { sorter.SortDirection = SortOrder.Descending; } else { sorter.SortDirection = SortOrder.Ascending; } return sorter; } 

下面是我的ListViewItemComparer

 public class ListViewItemComparer : IComparer { private int _columnIndex; public int ColumnIndex { get { return _columnIndex; } set { _columnIndex = value; } } private SortOrder _sortDirection; public SortOrder SortDirection { get { return _sortDirection; } set { _sortDirection = value; } } private ColumnDataType _columnType; public ColumnDataType ColumnType { get { return _columnType; } set { _columnType = value; } } public ListViewItemComparer() { _sortDirection = SortOrder.None; } public int Compare(object x, object y) { ListViewItem lviX = x as ListViewItem; ListViewItem lviY = y as ListViewItem; int result; if (lviX == null && lviY == null) { result = 0; } else if (lviX == null) { result = -1; } else if (lviY == null) { result = 1; } switch (ColumnType) { case ColumnDataType.DateTime: DateTime xDt = DataParseUtility.ParseDate(lviX.SubItems[ColumnIndex].Text); DateTime yDt = DataParseUtility.ParseDate(lviY.SubItems[ColumnIndex].Text); result = DateTime.Compare(xDt, yDt); break; case ColumnDataType.Decimal: Decimal xD = DataParseUtility.ParseDecimal(lviX.SubItems[ColumnIndex].Text.Replace("$", string.Empty).Replace(",", string.Empty)); Decimal yD = DataParseUtility.ParseDecimal(lviY.SubItems[ColumnIndex].Text.Replace("$", string.Empty).Replace(",", string.Empty)); result = Decimal.Compare(xD, yD); break; case ColumnDataType.Short: short xShort = DataParseUtility.ParseShort(lviX.SubItems[ColumnIndex].Text); short yShort = DataParseUtility.ParseShort(lviY.SubItems[ColumnIndex].Text); result = xShort.CompareTo(yShort); break; case ColumnDataType.Int: int xInt = DataParseUtility.ParseInt(lviX.SubItems[ColumnIndex].Text); int yInt = DataParseUtility.ParseInt(lviY.SubItems[ColumnIndex].Text); return xInt.CompareTo(yInt); break; case ColumnDataType.Long: long xLong = DataParseUtility.ParseLong(lviX.SubItems[ColumnIndex].Text); long yLong = DataParseUtility.ParseLong(lviY.SubItems[ColumnIndex].Text); return xLong.CompareTo(yLong); break; default: result = string.Compare( lviX.SubItems[ColumnIndex].Text, lviY.SubItems[ColumnIndex].Text, false); break; } if (SortDirection == SortOrder.Descending) { return -result; } else { return result; } } } 

我的解决方案是在单击列标题时对listView项进行排序的类。

您可以指定每列的类型。

 listView.ListViewItemSorter = new ListViewColumnSorter(); listView.ListViewItemSorter.ColumnsTypeComparer.Add(0, DateTime); listView.ListViewItemSorter.ColumnsTypeComparer.Add(1, int); 

而已 !

C#类:

 using System.Collections; using System.Collections.Generic; using EDV; namespace System.Windows.Forms { ///  /// Cette classe est une implémentation de l'interface 'IComparer' pour le tri des items de ListView. Adapté de http://support.microsoft.com/kb/319401. ///  /// Intégré par EDVariables. public class ListViewColumnSorter : IComparer { ///  /// Spécifie la colonne à trier ///  private int ColumnToSort; ///  /// Spécifie l'ordre de tri (en d'autres termes 'Croissant'). ///  private SortOrder OrderOfSort; ///  /// Objet de comparaison ne respectant pas les majuscules et minuscules ///  private CaseInsensitiveComparer ObjectCompare; ///  /// Constructeur de classe. Initialise la colonne sur '0' et aucun tri ///  public ListViewColumnSorter() : this(0, SortOrder.None) { } ///  /// Constructeur de classe. Initializes various elements /// Spécifie la colonne à trier /// Spécifie l'ordre de tri ///  public ListViewColumnSorter(int columnToSort, SortOrder orderOfSort) { // Initialise la colonne ColumnToSort = columnToSort; // Initialise l'ordre de tri OrderOfSort = orderOfSort; // Initialise l'objet CaseInsensitiveComparer ObjectCompare = new CaseInsensitiveComparer(); // Dictionnaire de comparateurs ColumnsComparer = new Dictionary(); ColumnsTypeComparer = new Dictionary(); } ///  /// Cette méthode est héritée de l'interface IComparer. Il compare les deux objets passés en effectuant une comparaison ///qui ne tient pas compte des majuscules et des minuscules. /// 
Si le comparateur n'existe pas dans ColumnsComparer, CaseInsensitiveComparer est utilisé. ///
/// Premier objet à comparer /// Deuxième objet à comparer /// Le résultat de la comparaison. "0" si équivalent, négatif si 'x' est inférieur à 'y' ///et positif si 'x' est supérieur à 'y' public int Compare(object x, object y) { int compareResult; ListViewItem listviewX, listviewY; // Envoit les objets à comparer aux objets ListViewItem listviewX = (ListViewItem)x; listviewY = (ListViewItem)y; if (listviewX.SubItems.Count < ColumnToSort + 1 || listviewY.SubItems.Count < ColumnToSort + 1) return 0; IComparer objectComparer = null; Type comparableType = null; if (ColumnsComparer == null || !ColumnsComparer.TryGetValue(ColumnToSort, out objectComparer)) if (ColumnsTypeComparer == null || !ColumnsTypeComparer.TryGetValue(ColumnToSort, out comparableType)) objectComparer = ObjectCompare; // Compare les deux éléments if (comparableType != null) { //Conversion du type object valueX = listviewX.SubItems[ColumnToSort].Text; object valueY = listviewY.SubItems[ColumnToSort].Text; if (!edvTools.TryParse(ref valueX, comparableType) || !edvTools.TryParse(ref valueY, comparableType)) return 0; compareResult = (valueX as IComparable).CompareTo(valueY); } else compareResult = objectComparer.Compare(listviewX.SubItems[ColumnToSort].Text, listviewY.SubItems[ColumnToSort].Text); // Calcule la valeur correcte d'après la comparaison d'objets if (OrderOfSort == SortOrder.Ascending) { // Le tri croissant est sélectionné, renvoie des résultats normaux de comparaison return compareResult; } else if (OrderOfSort == SortOrder.Descending) { // Le tri décroissant est sélectionné, renvoie des résultats négatifs de comparaison return (-compareResult); } else { // Renvoie '0' pour indiquer qu'ils sont égaux return 0; } } /// /// Obtient ou définit le numéro de la colonne à laquelle appliquer l'opération de tri (par défaut sur '0'). /// public int SortColumn { set { ColumnToSort = value; } get { return ColumnToSort; } } /// /// Obtient ou définit l'ordre de tri à appliquer (par exemple, 'croissant' ou 'décroissant'). /// public SortOrder Order { set { OrderOfSort = value; } get { return OrderOfSort; } } /// /// Dictionnaire de comparateurs par colonne. ///
Pendant le tri, si le comparateur n'existe pas dans ColumnsComparer, CaseInsensitiveComparer est utilisé. ///
public Dictionary ColumnsComparer { get; set; } /// /// Dictionnaire de comparateurs par colonne. ///
Pendant le tri, si le comparateur n'existe pas dans ColumnsTypeComparer, CaseInsensitiveComparer est utilisé. ///
public Dictionary ColumnsTypeComparer { get; set; } } }

初始化ListView:

  Visual.WIN.ctrlListView.OnShown : eventSender.Columns.Clear(); eventSender.SmallImageList = edvWinForm.ImageList16; eventSender.ListViewItemSorter = new ListViewColumnSorter(); var col = eventSender.Columns.Add("Répertoire"); col.Width = 160; col.ImageKey = "Domain"; col = eventSender.Columns.Add("Fichier"); col.Width = 180; col.ImageKey = "File"; col = eventSender.Columns.Add("Date"); col.Width = 120; col.ImageKey = "DateTime"; eventSender.ListViewItemSorter.ColumnsTypeComparer.Add(col.Index, DateTime); col = eventSender.Columns.Add("Position"); col.TextAlign = HorizontalAlignment.Right; col.Width = 80; col.ImageKey = "Num"; eventSender.ListViewItemSorter.ColumnsTypeComparer.Add(col.Index, Int32); 

填写ListView:

 Visual.WIN.cmdSearch.OnClick : //non récursif et sans fonction ..ctrlListView:Items.Clear(); ..ctrlListView:Sorting = SortOrder.None; var group = ..ctrlListView:Groups.Add(DateTime.Now.ToString() , Path.Combine(..cboDir:Text, ..ctrlPattern1:Text) + " contenant " + ..ctrlSearch1:Text); var perf = Environment.TickCount; var files = new DirectoryInfo(..cboDir:Text).GetFiles(..ctrlPattern1:Text) var search = ..ctrlSearch1:Text; var ignoreCase = ..Search.IgnoreCase; //var result = new StringBuilder(); var dirLength : int = ..cboDir:Text.Length; var position : int; var added : int = 0; for(var i : int = 0; i < files.Length; i++){ var file = files[i]; if(search == "" || (position = File.ReadAllText(file.FullName).IndexOf(String(search) , StringComparison(ignoreCase ? StringComparison.InvariantCultureIgnoreCase : StringComparison.InvariantCulture))) > =0) { // result.AppendLine(file.FullName.Substring(dirLength) + "\tPos : " + pkvFile.Value); var item = ..ctrlListView:Items.Add(file.FullName.Substring(dirLength)); item.SubItems.Add(file.Name); item.SubItems.Add(File.GetLastWriteTime(file.FullName).ToString()); item.SubItems.Add(position.ToString("# ### ##0")); item.Group = group; ++added; } } group.Header += " : " + added + "/" + files.Length + " fichier(s)" + " en " + (Environment.TickCount - perf).ToString("# ##0 msec"); 

在ListView列上单击:

 Visual.WIN.ctrlListView.OnColumnClick : // Déterminer si la colonne sélectionnée est déjà la colonne triée. var sorter = eventSender.ListViewItemSorter; if ( eventArgs.Column == sorter .SortColumn ) { // Inverser le sens de tri en cours pour cette colonne. if (sorter.Order == SortOrder.Ascending) { sorter.Order = SortOrder.Descending; } else { sorter.Order = SortOrder.Ascending; } } else { // Définir le numéro de colonne à trier ; par défaut sur croissant. sorter.SortColumn = eventArgs.Column; sorter.Order = SortOrder.Ascending; } // Procéder au tri avec les nouvelles options. eventSender.Sort(); 

上面使用的函数edvTools.TryParse

 class edvTools { ///  /// Tente la conversion d'une valeur suivant un type EDVType ///  /// Référence de la valeur à convertir /// Type EDV en sortie ///  public static bool TryParse(ref object pValue, System.Type pType) { int lIParsed; double lDParsed; string lsValue; if (pValue == null) return false; if (pType.Equals(typeof(bool))) { bool lBParsed; if (pValue is bool) return true; if (double.TryParse(pValue.ToString(), out lDParsed)) { pValue = lDParsed != 0D; return true; } if (bool.TryParse(pValue.ToString(), out lBParsed)) { pValue = lBParsed; return true; } else return false; } if (pType.Equals(typeof(Double))) { if (pValue is Double) return true; if (double.TryParse(pValue.ToString(), out lDParsed) || double.TryParse(pValue.ToString().Replace(NumberDecimalSeparatorNOT, NumberDecimalSeparator), out lDParsed)) { pValue = lDParsed; return true; } else return false; } if (pType.Equals(typeof(int))) { if (pValue is int) return true; if (Int32.TryParse(pValue.ToString(), out lIParsed)) { pValue = lIParsed; return true; } else if (double.TryParse(pValue.ToString(), out lDParsed)) { pValue = (int)lDParsed; return true; } else return false; } if (pType.Equals(typeof(Byte))) { if (pValue is byte) return true; byte lByte; if (Byte.TryParse(pValue.ToString(), out lByte)) { pValue = lByte; return true; } else if (double.TryParse(pValue.ToString(), out lDParsed)) { pValue = (byte)lDParsed; return true; } else return false; } if (pType.Equals(typeof(long))) { long lLParsed; if (pValue is long) return true; if (long.TryParse(pValue.ToString(), out lLParsed)) { pValue = lLParsed; return true; } else if (double.TryParse(pValue.ToString(), out lDParsed)) { pValue = (long)lDParsed; return true; } else return false; } if (pType.Equals(typeof(Single))) { if (pValue is float) return true; Single lSParsed; if (Single.TryParse(pValue.ToString(), out lSParsed) || Single.TryParse(pValue.ToString().Replace(NumberDecimalSeparatorNOT, NumberDecimalSeparator), out lSParsed)) { pValue = lSParsed; return true; } else return false; } if (pType.Equals(typeof(DateTime))) { if (pValue is DateTime) return true; DateTime lDTParsed; if (DateTime.TryParse(pValue.ToString(), out lDTParsed)) { pValue = lDTParsed; return true; } else if (pValue.ToString().Contains("UTC")) //Date venant de JScript { if (_MonthsUTC == null) InitMonthsUTC(); string[] lDateParts = pValue.ToString().Split(' '); lDTParsed = new DateTime(int.Parse(lDateParts[5]), _MonthsUTC[lDateParts[1]], int.Parse(lDateParts[2])); lDateParts = lDateParts[3].ToString().Split(':'); pValue = lDTParsed.AddSeconds(int.Parse(lDateParts[0]) * 3600 + int.Parse(lDateParts[1]) * 60 + int.Parse(lDateParts[2])); return true; } else return false; } if (pType.Equals(typeof(Array))) { if (pValue is System.Collections.ICollection || pValue is System.Collections.ArrayList) return true; return pValue is System.Data.DataTable || pValue is string && (pValue as string).StartsWith("<"); } if (pType.Equals(typeof(DataTable))) { return pValue is System.Data.DataTable || pValue is string && (pValue as string).StartsWith("<"); } if (pType.Equals(typeof(System.Drawing.Bitmap))) { return pValue is System.Drawing.Image || pValue is byte[]; } if (pType.Equals(typeof(System.Drawing.Image))) { return pValue is System.Drawing.Image || pValue is byte[]; } if (pType.Equals(typeof(System.Drawing.Color))) { if (pValue is System.Drawing.Color) return true; if (pValue is System.Drawing.KnownColor) { pValue = System.Drawing.Color.FromKnownColor((System.Drawing.KnownColor)pValue); return true; } int lARGB; if (!int.TryParse(lsValue = pValue.ToString(), out lARGB)) { if (lsValue.StartsWith("Color [A=", StringComparison.InvariantCulture)) { foreach (string lsARGB in lsValue.Substring("Color [".Length, lsValue.Length - "Color []".Length).Split(',')) switch (lsARGB.TrimStart().Substring(0, 1)) { case "A": lARGB = int.Parse(lsARGB.Substring(2)) * 0x1000000; break; case "R": lARGB += int.Parse(lsARGB.TrimStart().Substring(2)) * 0x10000; break; case "G": lARGB += int.Parse(lsARGB.TrimStart().Substring(2)) * 0x100; break; case "B": lARGB += int.Parse(lsARGB.TrimStart().Substring(2)); break; default: break; } pValue = System.Drawing.Color.FromArgb(lARGB); return true; } if (lsValue.StartsWith("Color [", StringComparison.InvariantCulture)) { pValue = System.Drawing.Color.FromName(lsValue.Substring("Color [".Length, lsValue.Length - "Color []".Length)); return true; } return false; } pValue = System.Drawing.Color.FromArgb(lARGB); return true; } if (pType.IsEnum) { try { if (pValue == null) return false; if (pValue is int || pValue is byte || pValue is ulong || pValue is long || pValue is double) pValue = Enum.ToObject(pType, pValue); else pValue = Enum.Parse(pType, pValue.ToString()); } catch { return false; } } return true; } } 

对此文章进行了一些细微的更改,以适应ListView中字符串和数值的排序。

Form1.cs包含

 using System; using System.Windows.Forms; namespace ListView { public partial class Form1 : Form { Random rnd = new Random(); private ListViewColumnSorter lvwColumnSorter; public Form1() { InitializeComponent(); // Create an instance of a ListView column sorter and assign it to the ListView control. lvwColumnSorter = new ListViewColumnSorter(); this.listView1.ListViewItemSorter = lvwColumnSorter; InitListView(); } private void InitListView() { listView1.View = View.Details; listView1.GridLines = true; listView1.FullRowSelect = true; //Add column header listView1.Columns.Add("Name", 100); listView1.Columns.Add("Price", 70); listView1.Columns.Add("Trend", 70); for (int i = 0; i < 10; i++) { listView1.Items.Add(AddToList("Name" + i.ToString(), rnd.Next(1, 100).ToString(), rnd.Next(1, 100).ToString())); } } private ListViewItem AddToList(string name, string price, string trend) { string[] array = new string[3]; array[0] = name; array[1] = price; array[2] = trend; return (new ListViewItem(array)); } private void listView1_ColumnClick(object sender, ColumnClickEventArgs e) { // 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. this.listView1.Sort(); } } } 

ListViewColumnSorter.cs包含

 using System; using System.Collections; using System.Windows.Forms; ///  /// This class is an implementation of the 'IComparer' interface. ///  public class ListViewColumnSorter : IComparer { ///  /// Specifies the column to be sorted ///  private int ColumnToSort; ///  /// Specifies the order in which to sort (ie 'Ascending'). ///  private SortOrder OrderOfSort; ///  /// Case insensitive comparer object ///  private CaseInsensitiveComparer ObjectCompare; ///  /// Class constructor. Initializes various elements ///  public ListViewColumnSorter() { // Initialize the column to '0' ColumnToSort = 0; // Initialize the sort order to 'none' OrderOfSort = SortOrder.None; // Initialize the CaseInsensitiveComparer object ObjectCompare = new CaseInsensitiveComparer(); } ///  /// This method is inherited from the IComparer interface. It compares the two objects passed using a case insensitive comparison. ///  /// First object to be compared /// Second object to be compared /// The result of the comparison. "0" if equal, negative if 'x' is less than 'y' and positive if 'x' is greater than 'y' public int Compare(object x, object y) { int compareResult; ListViewItem listviewX, listviewY; // Cast the objects to be compared to ListViewItem objects listviewX = (ListViewItem)x; listviewY = (ListViewItem)y; decimal num = 0; if (decimal.TryParse(listviewX.SubItems[ColumnToSort].Text, out num)) { compareResult = decimal.Compare(num, Convert.ToDecimal(listviewY.SubItems[ColumnToSort].Text)); } else { // Compare the two items compareResult = ObjectCompare.Compare(listviewX.SubItems[ColumnToSort].Text, listviewY.SubItems[ColumnToSort].Text); } // 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; } } ///  /// Gets or sets the number of the column to which to apply the sorting operation (Defaults to '0'). ///  public int SortColumn { set { ColumnToSort = value; } get { return ColumnToSort; } } ///  /// Gets or sets the order of sorting to apply (for example, 'Ascending' or 'Descending'). ///  public SortOrder Order { set { OrderOfSort = value; } get { return OrderOfSort; } } } 

我可以看到这个问题最初是在5年前发布的,当时程序员必须更加努力地获得他们想要的结果。 使用Visual Studio 2012及更高版本,懒惰的程序员可以进入Listview属性设置的Design View,然后单击Properties-> Sorting,选择Ascending。 还有很多其他属性function可以获得懒惰(又称智能)程序员可以利用的各种结果。

晚会,这是一个短暂的。 它有以下局限:

  • 它只对SubItemsTexts进行简单的字符串排序
  • 它使用ListViewTag
  • 它假定所有单击的列都将被填充

您可以注册和取消注册任何ListView到其服务; 确保Sorting设置为None ..:

 public static class LvSort { static List LVs = new List(); public static void registerLV(ListView lv) { if (!LVs.Contains(lv) && lv is ListView) { LVs.Add(lv); lv.ColumnClick +=Lv_ColumnClick; } } public static void unRegisterLV(ListView lv) { if (LVs.Contains(lv) && lv is ListView) { LVs.Remove(lv); lv.ColumnClick -=Lv_ColumnClick; } } private static void Lv_ColumnClick(object sender, ColumnClickEventArgs e) { ListView lv = sender as ListView; if (lv == null) return; int c = e.Column; bool asc = (lv.Tag == null) &&( lv.Tag.ToString() != c+""); var items = lv.Items.Cast().ToList(); var sorted = asc ? items.OrderByDescending(x => x.SubItems[c].Text).ToList() : items.OrderBy(x => x.SubItems[c].Text).ToList(); lv.Items.Clear(); lv.Items.AddRange(sorted.ToArray()); if (asc) lv.Tag = c+""; else lv.Tag = null; } } 

注册只需做..:

 public Form1() { InitializeComponent(); LvSort.registerLV(yourListView1); } 

更新:

这是一个稍微扩展的版本,它允许您使用您提出的任何排序规则对各种数据类型进行排序。 您需要做的就是为数据编写特殊的字符串转换,将其添加到函数列表并标记列。 为此,只需在列标记中添加标记字符串后面的列名称即可。

我添加了一个用于排序DataTimes和一个用于整数。

此版本还将对锯齿状ListView进行排序,即具有不同子项数量的ListView。

 public static class LvCtl { static List LVs = new List(); delegate string StringFrom (string s); static Dictionary funx = new Dictionary(); public static void registerLV(ListView lv) { if (!LVs.Contains(lv) && lv is ListView) { LVs.Add(lv); lv.ColumnClick +=Lv_ColumnClick; funx.Add("", stringFromString); for (int i = 0; i < lv.Columns.Count; i++) { if (lv.Columns[i].Tag == null) continue; string n = lv.Columns[i].Tag.ToString(); if (n == "") continue; if (n.Contains("__date")) funx.Add(n, stringFromDate); if (n.Contains("__int")) funx.Add(n, stringFromInt); else funx.Add(n, stringFromString); } } } static string stringFromString(string s) { return s; } static string stringFromInt(string s) { int i = 0; int.TryParse(s, out i); return i.ToString("00000") ; } static string stringFromDate(string s) { DateTime dt = Convert.ToDateTime(s); return dt.ToString("yyyy.MM.dd HH.mm.ss"); } private static void Lv_ColumnClick(object sender, ColumnClickEventArgs e) { ListView lv = sender as ListView; if (lv == null) return; int c = e.Column; string nt = lv.Columns[c].Tag.ToString(); string n = nt.Replace("__", "§").Split('§')[0]; bool asc = (lv.Tag == null) || ( lv.Tag.ToString() != c+""); var items = lv.Items.Cast().ToList(); var sorted = asc? items.OrderByDescending(x => funx[nt]( c < x.SubItems.Count ? x.SubItems[c].Text: "")).ToList() : items.OrderBy(x => funx[nt](c < x.SubItems.Count ? x.SubItems[c].Text : "")).ToList(); lv.Items.Clear(); lv.Items.AddRange(sorted.ToArray()); if (asc) lv.Tag = c+""; else lv.Tag = null; } public static void unRegisterLV(ListView lv) { if (LVs.Contains(lv) && lv is ListView) { LVs.Remove(lv); lv.ColumnClick -=Lv_ColumnClick; } } } 

我会推荐你​​的datagridview,重要的东西..它包括很多汽车functionlistviwe没有

使用ListView.SortExpression 。

排序多个列时,此属性包含要排序的字段的逗号分隔列表。

您可以使用这样的手动排序算法

 public void ListItemSorter(object sender, ColumnClickEventArgs e) { ListView list = (ListView)sender; int total = list.Items.Count; list.BeginUpdate(); ListViewItem[] items = new ListViewItem[total]; for (int i = 0; i < total; i++) { int count = list.Items.Count; int minIdx = 0; for (int j = 1; j < count; j++) if (list.Items[j].SubItems[e.Column].Text.CompareTo(list.Items[minIdx].SubItems[e.Column].Text) < 0) minIdx = j; items[i] = list.Items[minIdx]; list.Items.RemoveAt(minIdx); } list.Items.AddRange(items); list.EndUpdate(); } 

此方法使用O ^ 2顺序的选择排序和Ascending。 您可以使用“<”更改“>”以进行降序或为此方法添加参数。 它对任何单击的列进行排序,适用于少量数据。

由于这仍然是一个顶级浏览的线程,我想我可能会注意到我想出了一个动态解决方案来按列对列表视图进行排序。 这是代码,以防万一其他人也想使用它。 它几乎只涉及将listview项发送到数据表,通过列名(使用单击列的索引)对数据表的默认视图进行排序,然后使用defaultview.totable()方法覆盖该表。 然后几乎只是将它们添加回列表视图。 并且wa la,它是按列排序的列表视图。

 public void SortListView(int Index) { DataTable TempTable = new DataTable(); //Add column names to datatable from listview foreach (ColumnHeader iCol in MyListView.Columns) { TempTable.Columns.Add(iCol.Text); } //Create a datarow from each listviewitem and add it to the table foreach (ListViewItem Item in MyListView.Items) { DataRow iRow = TempTable.NewRow(); // the for loop dynamically copies the data one by one instead of doing irow[i] = MyListView.Subitems[1]... so on for (int i = 0; i < MyListView.Columns.Count; i++) { if (i == 0) { iRow[i] = Item.Text; } else { iRow[i] = Item.SubItems[i].Text; } } TempTable.Rows.Add(iRow); } string SortType = string.Empty; //LastCol is a public int variable on the form, and LastSort is public string variable if (LastCol == Index) { if (LastSort == "ASC" || LastSort == string.Empty || LastSort == null) { SortType = "DESC"; LastSort = "DESC"; } else { SortType = "ASC"; LastSort = "ASC"; } } else { SortType = "DESC"; LastSort = "DESC"; } LastCol = Index; MyListView.Items.Clear(); //Sort it based on the column text clicked and the sort type (asc or desc) TempTable.DefaultView.Sort = MyListView.Columns[Index].Text + " " + SortType; TempTable = TempTable.DefaultView.ToTable(); //Create a listview item from the data in each row foreach (DataRow iRow in TempTable.Rows) { ListViewItem Item = new ListViewItem(); List SubItems = new List(); for (int i = 0; i < TempTable.Columns.Count; i++) { if (i == 0) { Item.Text = iRow[i].ToString(); } else { SubItems.Add(iRow[i].ToString()); } } Item.SubItems.AddRange(SubItems.ToArray()); MyListView.Items.Add(Item); } } 

此方法是动态的,因为它使用现有列名称,并且不需要您知道每列的索引或名称,甚至不需要知道listview / datatable中有多少列。 You can call it by doing creating an event for the listview.columnclick and then SortListView(e.column).

Based on the example pointed by RedEye, here’s a class that needs less code :
it assumes that columns are always sorted in the same way, so it handles the
ColumnClick event sink internally :

 public class ListViewColumnSorterExt : IComparer { ///  /// Specifies the column to be sorted ///  private int ColumnToSort; ///  /// Specifies the order in which to sort (ie 'Ascending'). ///  private SortOrder OrderOfSort; ///  /// Case insensitive comparer object ///  private CaseInsensitiveComparer ObjectCompare; private ListView listView; ///  /// Class constructor. Initializes various elements ///  public ListViewColumnSorterExt(ListView lv) { listView = lv; listView.ListViewItemSorter = this; listView.ColumnClick += new ColumnClickEventHandler(listView_ColumnClick); // Initialize the column to '0' ColumnToSort = 0; // Initialize the sort order to 'none' OrderOfSort = SortOrder.None; // Initialize the CaseInsensitiveComparer object ObjectCompare = new CaseInsensitiveComparer(); } private void listView_ColumnClick(object sender, ColumnClickEventArgs e) { ReverseSortOrderAndSort(e.Column, (ListView)sender); } ///  /// This method is inherited from the IComparer interface. It compares the two objects passed using a case insensitive comparison. ///  /// First object to be compared /// Second object to be compared /// The result of the comparison. "0" if equal, negative if 'x' is less than 'y' and positive if 'x' is greater than 'y' public int Compare(object x, object y) { int compareResult; ListViewItem listviewX, listviewY; // Cast the objects to be compared to ListViewItem objects listviewX = (ListViewItem)x; listviewY = (ListViewItem)y; // Compare the two items compareResult = ObjectCompare.Compare(listviewX.SubItems[ColumnToSort].Text, listviewY.SubItems[ColumnToSort].Text); // 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; } } ///  /// Gets or sets the number of the column to which to apply the sorting operation (Defaults to '0'). ///  private int SortColumn { set { ColumnToSort = value; } get { return ColumnToSort; } } ///  /// Gets or sets the order of sorting to apply (for example, 'Ascending' or 'Descending'). ///  private SortOrder Order { set { OrderOfSort = value; } get { return OrderOfSort; } } private void ReverseSortOrderAndSort(int column, ListView lv) { // Determine if clicked column is already the column that is being sorted. if (column == this.SortColumn) { // Reverse the current sort direction for this column. if (this.Order == SortOrder.Ascending) { this.Order = SortOrder.Descending; } else { this.Order = SortOrder.Ascending; } } else { // Set the column number that is to be sorted; default to ascending. this.SortColumn = column; this.Order = SortOrder.Ascending; } // Perform the sort with these new sort options. lv.Sort(); } } 

Assuming you’re happy with the sort options, the class properties are private .

The only code you need to write is :

in Form declarations

 private ListViewColumnSorterExt listViewColumnSorter; 

in Form constructor

 listViewColumnSorter = new ListViewColumnSorterExt(ListView1); 

… and you’re done.

And what about a single sorter that handles multiple ListViews ?

 public class MultipleListViewColumnSorter { private List sorters; public MultipleListViewColumnSorter() { sorters = new List(); } public void AddListView(ListView lv) { sorters.Add(new ListViewColumnSorterExt(lv)); } } 

in Form declarations

 private MultipleListViewColumnSorter listViewSorter = new MultipleListViewColumnSorter(); 

in Form constructor

 listViewSorter.AddListView(ListView1); listViewSorter.AddListView(ListView2); // ... and so on ... 

I slightly modified the example from Microsoft: https://support.microsoft.com/en-us/kb/319401

This method will only sort once to sort ascending. My modifications make it sort both ways.

 public class ListViewItemComparer : IComparer { private int col; bool bAsc = false; public ListViewItemComparer() { col = 0; } public ListViewItemComparer(int column, bool b) { col = column; bAsc = b; } public int Compare(object x, object y) { if (bAsc) { return String.Compare(((ListViewItem)x).SubItems[col].Text, ((ListViewItem)y).SubItems[col].Text); bAsc = false; } else { return String.Compare(((ListViewItem)y).SubItems[col].Text, ((ListViewItem)x).SubItems[col].Text); bAsc = true; } } } 

Then I create an object of this class whenever a column header is clicked

  bool sortAscending = false; private void inventoryList_ColumnClick(object sender, ColumnClickEventArgs e) { if (!sortAscending) { sortAscending = true; } else { sortAscending = false; } this.inventoryList.ListViewItemSorter = new ListViewItemComparer(e.Column, sortAscending); }