2009-10-10 3 views
16

В настоящее время я использую пользовательский сортировщик в списке, и я могу сортировать 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; 
    } 
} 

Это прекрасно работает при сортировке в первом столбце, но если вы должны были сделать это на любой другой колонке, это было бы просто отсортировать по первому столбцу. Есть ли способ сортировки по столбцу?

+0

Майк, если вы посмотрите на мой пример ниже, я думаю, что вы ищете значение ColumnClickEventArgs.Column. Он скажет вам, какой заголовок столбца был нажат. –

ответ

20

Если вы начинаете с ListView, сделайте себе огромную пользу и вместо этого используйте ObjectListView. ObjectListView - это оболочка с открытым исходным кодом в среде .NET WinForms ListView, которая упрощает использование ListView и решает множество общих проблем для вас. Сортировка по щелчку столбца - это одна из многих задач, которые она обрабатывает для вас автоматически.

Серьезно, вы никогда не пожалеете об использовании ObjectListView вместо обычного ListView.

+10

Я использовал ObjectListView раньше и понравился. Единственное, что вы должны знать, это то, что это GPL, поэтому вам, возможно, придется выпустить исходный код. – Slapout

+0

* может * придется? Кто-нибудь знает, можем ли мы использовать GPL или нет? Я действительно хочу знать, могу ли я законно использовать его в коммерческом программном обеспечении, которое продается, а не в open-source? (в Европе и США) – noelicus

+0

Если вы хотите использовать это в закрытом исходном приложении, вы можете купить (дешевую) лицензию: http://objectlistview.sourceforge.net/cs/faq.html#can-i-use- objectlistview-in-a-commercial-application – Grammarian

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 –

+0

При создании вашего ListViewitemComparer на основе ссылки, приведенной выше, вам нужно будет добавить этот код для сортировки по возрастанию/убыванию: string itemXText = itemX.SubItems [Column] .Text; string itemYText = itemY.SubItems [Column] .Text; // сортировка если (itemX.ListView.Sorting == SortOrder.Ascending) { возвращение String.Compare (itemXText, itemYText); } else { return String.Compare (itemYText, itemXText); } –

+0

@ will-p Не могли бы вы показать, как выглядит ListViewItemComparer? – slayernoah

0

я бы порекомендовал вам вы DataGridView, для тяжелых вещей .. это включает много авто особенность listviwe не

0

Используйте ListView.SortExpression.

Когда несколько столбцов сортируются, это свойство содержит разделенный запятыми список полей для сортировки.

+0

Речь идет о веб-элементах управления ASP.NET, а не о Windows Forms. – ygoe

21

Забудьте о своем обычном сортировщике. Начните с использования кода на следующей странице. Он покажет вам, как определить класс, который наследуется от интерфейса IComparer. Каждая строка закомментирована, поэтому вы можете увидеть, что происходит. Единственным потенциальным осложнением является то, как вы извлекаете свои элементы списка из своего элемента управления Listview. Получите эти квадраты, и все, что вам нужно сделать, это скопировать и вставить класс интерфейса IComparer и метод columnClick.

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

+2

Очень полезная ссылка. Кажется, это самое простое решение. Спасибо, RedEye. – Martin

+1

Или еще лучше, используйте приведенный выше код, чтобы создать свой собственный SortableListView, тогда все, что вам нужно изменить, - это одна строка, в которой ваш список инициализирован. –

+1

Поскольку код в приемнике является довольно стандартным поведением, Я добавил ** метод ** ReverseSortOrderAndSort (int column, ListView lv) ** в класс ** ListViewColumnSorter ** , поэтому код в приемнике станет следующим: private void listView1_ColumnClick (отправитель объекта, ColumnClickEventArgs e) { listViewColumnSorter.ReverseSortOrderAndSort (e.Column, (ListView) отправитель); } –

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

Поскольку это все еще просматриваемая тема, я подумал, что могу заметить, что я разработал динамическое решение для сортировки списка по столбцу. Вот код на тот случай, если кто-то еще захочет использовать его. В основном это связано с отправкой элементов listview в datatable, сортировкой представления по умолчанию для datatable по имени столбца (с использованием индекса щелкнутого столбца), а затем перезаписи этой таблицы методом 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<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/DataTable. Вы можете вызвать его, создав событие для 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

На примере указываемого RedEye, вот это класс, который требует меньше коды:
он предполагает, что столбцы всегда сортируется таким же образом, поэтому обрабатывает
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(); 
    } 
} 

Предполагая, что вы счастливы с параметрами сортировки, свойства класса являются частные.

Единственный код, который нужно написать это:

в объявлениях Форма

private ListViewColumnSorterExt listViewColumnSorter; 

в форме конструктора

listViewColumnSorter = new ListViewColumnSorterExt(ListView1); 

... и вы сделали.

А как насчет одного сортировщика, который обрабатывает несколько списков 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 и более поздними версиями, ленивый программист может перейти в Design View для параметров свойств Listview и щелкнуть Properties -> Sorting, выбрать Ascending. Существует множество других свойств, чтобы получить различные результаты, которые может использовать ленивый (ака умный) программист.

0

Я слегка модифицированный пример из Microsoft: 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

Late к партии, вот короткий один. Она имеет следующие ограничения:

  • Это делает только простой строковый вид на SubItems «Texts
  • Он использует ListView» s Tag
  • Он принимает все щелкнул столбцы будут заполнены

Вы можете зарегистрировать &, отмените регистрацию на адрес компании 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); 
} 

Update:

Вот немного расширенная версия, которая позволит вам сортировать все виды типов данных с использованием любого правила сортировки вы придумали. Все, что вам нужно сделать, это написать специальное преобразование строк для ваших данных, добавить его в список функций и пометить столбцы. Для этого просто поместите имена столбцов, добавленные в строку маркера в тегах столбцов.

Я добавил один для сортировки DataTimes и один для целых чисел.

Эта версия также сортирует обработанные ListViews, т. Е. Те, у которых разное количество подэлементов.

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; 
     } 
    } 
} 
Смежные вопросы