2009-10-10 244 views
16

當前我在列表視圖上使用自定義排序器,每次單擊第一列時我都可以對列表視圖進行排序,但不會按其他列排序。按列排序列表視圖

SortStyle:變量以確定它是Ascending Sort還是Descending。

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

此排序爲第一列時工作正常,但如果你做任何其他列,它只是排序的第一列。有沒有一種方法可以通過點擊列進行排序?

+0

邁克,如果你看看我的例子下面我認爲你正在尋找ColumnClickEventArgs.Column值。它會告訴你哪個列標題被點擊。 – 2009-10-10 17:30:49

回答

20

如果你開始了與一個ListView,做自己的一個巨大的忙,並使用ObjectListView來代替。 ObjectListView是.NET WinForms ListView的開放源碼包裝,它使ListView更易於使用併爲您解決了許多常見問題。按列點擊排序是它自動處理的許多事情之一。

說真的,你永遠不會後悔使用ObjectListView而不是普通的ListView。

+10

我已經使用過ObjectListView並且喜歡它。您必須注意的一件事是它是GPL,因此您可能必須發佈您的源代碼。 – Slapout 2012-03-13 18:22:59

+0

*可能*必須?有誰知道我們是否可以使用GPL?我真正想知道的是:我可以合法地將它用於已售出而不是開源的商業軟件嗎? (在歐洲和美國) – noelicus 2012-09-26 11:05:15

+0

如果您想在封閉源代碼應用程序中使用它,您可以購買(便宜)許可證:http://objectlistview.sourceforge.net/cs/faq.html#can-i-use- objectlistview-in-commercial-application – Grammarian 2012-09-28 04:11:45

5

我使用列名進行排序以設置可能需要根據存儲在列中的數據類型處理的任何排序細節,或者如果列已經排序(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; 
     } 
    } 
} 
+0

此頁面提供了一個類似的解決方案 - > http://www.java2s.com/Tutorial/CSharp/0460__GUI-Windows-Forms/ListViewSorter.htm – 2011-09-01 17:02:20

+0

當根據我在上面提供的鏈接創建ListViewitemComparer時,您需要添加此代碼獲取升序/降序排序:字符串itemXText = itemX.SubItems [Column] .Text; string itemYText = itemY.SubItems [Column] .Text; //排序 if(itemX.ListView.Sorting == SortOrder.Ascending) { return String.Compare(itemXText,itemYText); } else { return String.Compare(itemYText,itemXText); } – 2011-09-01 17:29:22

+0

@ will-p你能展示一下ListViewItemComparer的外觀嗎? – slayernoah 2016-03-15 21:29:42

0

我建議你向你的DataGridView,重的東西..它包括了很多自動功能listviwe並不

0

使用ListView.SortExpression

當多個列進行排序,這 屬性包含的字段的逗號分隔 列表進行排序。

+0

這是關於ASP.NET Web控件的,而不是Windows窗體。 – ygoe 2015-03-07 15:19:02

21

忘掉你的自定義分類器。重新開始使用下一頁的代碼。它將向您展示如何定義從IComparer接口繼承的類。每一行都被註釋掉了,所以你可以真正看到發生了什麼。唯一可能的複雜情況是您如何從Listview控件中檢索Listview項目。讓那些擺脫方向,你需要做的就是複製和粘貼IComparer接口類和columnClick方法。

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

+2

非常有用的鏈接。似乎是最簡單的解決方案。謝謝RedEye。 – Martin 2014-09-10 07:26:03

+1

或更好的是,使用上面鏈接的代碼創建您自己的SortableListView,然後您需要更改的只是列表初始化的一行。 – 2014-10-20 17:21:18

+1

由於事件接收器中的代碼是相當標準的行爲,我向** ListViewColumnSorter **類 添加了** ReverseSortOrderAndSort(int列,ListView lv)**方法,因此事件接收器中的代碼變爲: private void listView1_ColumnClick(object sender,ColumnClickEventArgs e){listviewColumnSorter.ReverseSortOrderAndSort(e.Column,(ListView)sender); } – 2014-11-22 13:58:55

2

我的解決辦法是,當你點擊列標題的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 
{ 
    /// <summary> 
    /// 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. 
    /// </summary> 
    /// <remarks>Intégré par EDVariables.</remarks> 
    public class ListViewColumnSorter : IComparer 
    { 
     /// <summary> 
     /// Spécifie la colonne à trier 
     /// </summary> 
     private int ColumnToSort; 
     /// <summary> 
     /// Spécifie l'ordre de tri (en d'autres termes 'Croissant'). 
     /// </summary> 
     private SortOrder OrderOfSort; 
     /// <summary> 
     /// Objet de comparaison ne respectant pas les majuscules et minuscules 
     /// </summary> 
     private CaseInsensitiveComparer ObjectCompare; 

     /// <summary> 
     /// Constructeur de classe. Initialise la colonne sur '0' et aucun tri 
     /// </summary> 
     public ListViewColumnSorter() 
      : this(0, SortOrder.None) { } 

     /// <summary> 
     /// Constructeur de classe. Initializes various elements 
     /// <param name="columnToSort">Spécifie la colonne à trier</param> 
     /// <param name="orderOfSort">Spécifie l'ordre de tri</param> 
     /// </summary> 
     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<int, IComparer>(); 
      ColumnsTypeComparer = new Dictionary<int, Type>(); 

     } 

     /// <summary> 
     /// 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. 
     /// <br/>Si le comparateur n'existe pas dans ColumnsComparer, CaseInsensitiveComparer est utilisé. 
     /// </summary> 
     /// <param name="x">Premier objet à comparer</param> 
     /// <param name="x">Deuxième objet à comparer</param> 
     /// <returns>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'</returns> 
     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; 
      } 
     } 

     /// <summary> 
     /// Obtient ou définit le numéro de la colonne à laquelle appliquer l'opération de tri (par défaut sur '0'). 
     /// </summary> 
     public int SortColumn 
     { 
      set 
      { 
       ColumnToSort = value; 
      } 
      get 
      { 
       return ColumnToSort; 
      } 
     } 

     /// <summary> 
     /// Obtient ou définit l'ordre de tri à appliquer (par exemple, 'croissant' ou 'décroissant'). 
     /// </summary> 
     public SortOrder Order 
     { 
      set 
      { 
       OrderOfSort = value; 
      } 
      get 
      { 
       return OrderOfSort; 
      } 
     } 

     /// <summary> 
     /// Dictionnaire de comparateurs par colonne. 
     /// <br/>Pendant le tri, si le comparateur n'existe pas dans ColumnsComparer, CaseInsensitiveComparer est utilisé. 
     /// </summary> 
     public Dictionary<int, IComparer> ColumnsComparer { get; set; } 

     /// <summary> 
     /// Dictionnaire de comparateurs par colonne. 
     /// <br/>Pendant le tri, si le comparateur n'existe pas dans ColumnsTypeComparer, CaseInsensitiveComparer est utilisé. 
     /// </summary> 
     public Dictionary<int, Type> ColumnsTypeComparer { get; set; } 
    } 
} 

初始化一個ListView:

<var>Visual.WIN.ctrlListView.OnShown</var> : 
    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:

<var>Visual.WIN.cmdSearch.OnClick</var> : 
//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 &lt; files.Length; i++){ 
     var file = files[i]; 
     if(search == "" 
     || (position = File.ReadAllText(file.FullName).IndexOf(String(search) 
          , StringComparison(ignoreCase ? StringComparison.InvariantCultureIgnoreCase : StringComparison.InvariantCulture))) &gt; =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中列點擊:

<var>Visual.WIN.ctrlListView.OnColumnClick</var> : 
// 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 { 
    /// <summary> 
    /// Tente la conversion d'une valeur suivant un type EDVType 
    /// </summary> 
    /// <param name="pValue">Référence de la valeur à convertir</param> 
    /// <param name="pType">Type EDV en sortie</param> 
    /// <returns></returns> 
    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; 
    } 
} 
0

可以使用手動排序算法這樣

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的順序和升序選擇排序。您可以將'>'更改爲'<',以降序或爲此方法添加參數。 它對任何被點擊的列進行排序,並且適用於少量數據。

0

由於這仍然是一個頂級看線程,我想我可能會注意到,我想出了一個動態的解決方案,按列排序列表視圖。這是代碼,以防其他人也想使用它。它幾乎只涉及將列表視圖項發送到數據表,通過列名(使用單擊列的索引)對數據表的默認視圖進行排序,然後使用defaultview.totable()方法覆蓋該表。然後幾乎把它們添加回列表視圖。而且,它是按列分類的列表視圖。

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<string> SubItems = new List<string>(); 
      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.columnclick創建一個事件然後SortListView(e.column)來調用它。

1

對文章here進行了小修改,以適應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; 

/// <summary> 
/// This class is an implementation of the 'IComparer' interface. 
/// </summary> 
public class ListViewColumnSorter : IComparer 
{ 
    /// <summary> 
    /// Specifies the column to be sorted 
    /// </summary> 
    private int ColumnToSort; 
    /// <summary> 
    /// Specifies the order in which to sort (i.e. 'Ascending'). 
    /// </summary> 
    private SortOrder OrderOfSort; 
    /// <summary> 
    /// Case insensitive comparer object 
    /// </summary> 
    private CaseInsensitiveComparer ObjectCompare; 

    /// <summary> 
    /// Class constructor. Initializes various elements 
    /// </summary> 
    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(); 
    } 

    /// <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; 
     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; 
     } 
    } 

    /// <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; 
     } 
    } 

} 
0

基於由紅眼指出的例子,這裏是一個需要更少的代碼A類:
它假定列始終以相同的方式排序,所以它處理
ColumnClick事件沉在內部:

public class ListViewColumnSorterExt : IComparer { 
    /// <summary> 
    /// Specifies the column to be sorted 
    /// </summary> 
    private int ColumnToSort; 
    /// <summary> 
    /// Specifies the order in which to sort (i.e. 'Ascending'). 
    /// </summary> 
    private SortOrder OrderOfSort; 
    /// <summary> 
    /// Case insensitive comparer object 
    /// </summary> 
    private CaseInsensitiveComparer ObjectCompare; 

    private ListView listView; 
    /// <summary> 
    /// Class constructor. Initializes various elements 
    /// </summary> 
    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); 
    } 

    /// <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; 
     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; 
     } 
    } 

    /// <summary> 
    /// Gets or sets the number of the column to which to apply the sorting operation (Defaults to '0'). 
    /// </summary> 
    private int SortColumn { 
     set { 
      ColumnToSort = value; 
     } 
     get { 
      return ColumnToSort; 
     } 
    } 

    /// <summary> 
    /// Gets or sets the order of sorting to apply (for example, 'Ascending' or 'Descending'). 
    /// </summary> 
    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(); 
    } 
} 

假設您對排序選項感到滿意,類屬性爲私有

你需要編寫的唯一代碼是:

表格申報表格構造

listViewColumnSorter = new ListViewColumnSorterExt(ListView1); 

private ListViewColumnSorterExt listViewColumnSorter; 

...你就大功告成了。

那麼處理多個ListView的單個分揀機又如何呢?

public class MultipleListViewColumnSorter { 
    private List<ListViewColumnSorterExt> sorters; 

    public MultipleListViewColumnSorter() { 
     sorters = new List<ListViewColumnSorterExt>(); 
    } 

    public void AddListView(ListView lv) { 
     sorters.Add(new ListViewColumnSorterExt(lv)); 
    } 
} 

表格聲明

private MultipleListViewColumnSorter listViewSorter = new MultipleListViewColumnSorter(); 

在窗體構造

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

我可以看到這個問題最初發布5年以前,當程序員不得不更加努力地工作,以得到他們想要的結果。 使用Visual Studio 2012及更高版本,懶惰的程序員可以進入Listview屬性設置的設計視圖,然後單擊屬性 - >排序,選擇升序。 還有很多其他屬性功能可以獲得懶惰(又名智能)程序員可以利用的各種結果。

0

我稍微從微軟修改例如:https://support.microsoft.com/en-us/kb/319401

這種方法只排序一次升序排序。我的修改使它對兩種方式進行排序。

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; 
     } 
    } 

} 

然後,我創建這個類的一個對象,只要一列標題點擊

 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); 

     } 
0

遲到了,這裏是一個簡短的一個。它具有以下限制:

  • 它只是做了簡單的字符串排序SubItems的「Texts
  • 它採用了ListViewTag
  • 它假定所有點擊字段將被填充

您可以註冊&註銷任何ListView到其服務;確保Sorting設置爲None ..:

public static class LvSort 
{ 
    static List<ListView> LVs = new List<ListView>(); 
    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<ListViewItem>().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<ListView> LVs = new List<ListView>(); 

    delegate string StringFrom (string s); 

    static Dictionary<string, StringFrom> funx = new Dictionary<string, StringFrom>(); 

    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<ListViewItem>().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; 
     } 
    } 
}