2009-07-31 15 views
6

Come faccio a ordinare le colonne di numeri interi in un ListViewcome faccio sorta interi in una lista

C#, .net 2.0, Winform

System.Windows.Forms.ListView

+1

ASP.NET? Windows Forms? –

+0

Ho modificato la mia risposta per includere un esempio completo, che può ordinare sia come testo che come numerico –

risposta

19

Ecco come ho potuto essere in grado di ordinare su più colonne e di ordinare ogni colonna come un numero o come testo.

Primo utilizzo questa classe:

class Sorter : System.Collections.IComparer 
{ 
    public int Column = 0; 
    public System.Windows.Forms.SortOrder Order = SortOrder.Ascending; 
    public int Compare(object x, object y) // IComparer Member 
    { 
     if (!(x is ListViewItem)) 
      return (0); 
     if (!(y is ListViewItem)) 
      return (0); 

     ListViewItem l1 = (ListViewItem)x; 
     ListViewItem l2 = (ListViewItem)y; 

     if (l1.ListView.Columns[Column].Tag == null) 
     { 
      l1.ListView.Columns[Column].Tag = "Text"; 
     } 

     if (l1.ListView.Columns[Column].Tag.ToString() == "Numeric") 
     { 
      float fl1 = float.Parse(l1.SubItems[Column].Text); 
      float fl2 = float.Parse(l2.SubItems[Column].Text); 

      if (Order == SortOrder.Ascending) 
      { 
       return fl1.CompareTo(fl2); 
      } 
      else 
      { 
       return fl2.CompareTo(fl1); 
      } 
     } 
     else 
     { 
      string str1 = l1.SubItems[Column].Text; 
      string str2 = l2.SubItems[Column].Text; 

      if (Order == SortOrder.Ascending) 
      { 
       return str1.CompareTo(str2); 
      } 
      else 
      { 
       return str2.CompareTo(str1); 
      } 
     } 
    } 
} 

nel costruttore del modulo, impostare il sorter in questo modo:

lvSeries.ListViewItemSorter = new Sorter(); 

Poi gestire il ColumnClick anche del controllo ListView in questo modo:

private void lvSeries_ColumnClick(object sender, ColumnClickEventArgs e) 
    { 
     Sorter s = (Sorter)lvSeries.ListViewItemSorter; 
     s.Column = e.Column; 

     if (s.Order == System.Windows.Forms.SortOrder.Ascending) 
     { 
      s.Order = System.Windows.Forms.SortOrder.Descending; 
     } 
     else 
     { 
      s.Order = System.Windows.Forms.SortOrder.Ascending; 
     } 
     lvSeries.Sort(); 
    } 

Tutto dipende dalla proprietà Tag di ogni colonna sia impostata su "Num eric "o no, quindi il sorter sa come ordinare.

Nell'esempio precedente lancio i valori come float quando numerici, potreste volerli cambiare in int.

+1

@Neil: li ordina come testo per impostazione predefinita. Per esempio. 100 viene prima di 3. Tuttavia, è possibile ordinare correttamente int con ListViewItemSorter personalizzato. –

+0

Ahh questo è giusto. string è il tipo predefinito. –

+0

Seguo l'esempio su http://support.microsoft.com/kb/319401 ma non ordina ancora correttamente gli interi. Testo di testo, come si imposta la colonna predefinita da ordinare. Ordina correttamente sulla colonna 1 ma non trovo la proprietà da impostare per la colonna su cui ordinare. – Brad

0

mi piacerebbe fallo nell'origine dati (modello) anziché nella vista. Ordinalo lì e dovrebbe aggiornarlo nella vista tramite il databinding.

+0

significa ordinare il datasouce, datatable nella mia istanza, e quindi ricaricare la listview quando viene cliccata una colonna? – Brad

+0

no, cattive abitudini da ricaricare ogni volta. Google "ListViewItemSorter" e ti mostrerà come ordinare per ogni colonna. –

+0

sì, è quello che pensavo. – Brad

3

Sarà necessario creare una classe che implementa l'interfaccia IComparer (quella non generica). In questa classe di leggere la proprietà Text dal sub-articolo corretto, convertirlo in int, e fare il confronto:

public class IntegerComparer : IComparer 
{ 
    private int _colIndex; 
    public IntegerComparer(int colIndex) 
    { 
     _colIndex = colIndex; 
    } 
    public int Compare(object x, object y) 
    { 
     int nx = int.Parse((x as ListViewItem).SubItems[_colIndex].Text); 
     int ny = int.Parse((y as ListViewItem).SubItems[_colIndex].Text); 
     return nx.CompareTo(ny); 
    } 
} 

Poi si assegna un tale di confronto alla proprietà ListViewItemSorter e invocare il metodo di ordinamento della ListView controllo:

// create a comparer for column index 1 and assign it to the control, and sort 
myListView.ListViewItemSorter = new IntegerComparer(1); 
myListView.Sort(); 
+0

alcune colonne sono numeriche altre sono testo ... dovrei testare per numerico prima dell'ordinamento? – Brad

+1

Una volta ho fatto un comparatore ListViewItem che esaminava ogni elemento accoppiare nel metodo Compare, ma questo è diventato piuttosto lento. Sarà meglio avere comparatori separati e scegliere quale utilizzare in base a quale colonna viene ordinata, o creare una classe di confronto in cui si passa un valore al costruttore che indica se per fare un ordinamento basato su numeri, date o testo e poi passare al metodo Confronto basato su quel valore (che era la soluzione che ho scelto in quel caso) –

+0

Buona idea, ma ho creato una variabile privata come 'sortType' all'interno del mio listview confronta cla ss invece. – Chris

5

Se iniziato con un controllo ListView, la vostra vita sarà molto più facile se si utilizza un ObjectListView invece. ObjectListView è un wrapper open source su .NET WinForms ListView, e risolve tutti questi fastidiosi piccoli problemi che normalmente rendono il lavoro con un ListView così frustrante. Ad esempio, ordina automaticamente ints in modo che '100' venga dopo '3' (DateTimes, bool e tutto il resto ordina anche correttamente).

Seriamente, non si vorrà più tornare a un ListView semplice dopo aver utilizzato ObjectListView.

Sì, sono l'autore - ma ciò non significa che io sia di parte ... OK, beh forse lo fa :) Guarda here per le opinioni di altre persone.

+0

Grazie ... gli darò un test drive al momento – Brad

0

Ho usato la classe Neil-N ma ho modificato l'istruzione if per testare la proprietà Type anziché la proprietà Tag. Ho impostato ogni colonna su Type Number (anziché su Text) che conteneva un valore intero. Ordina funziona alla grande.

if (l1.ListView.Columns[Column].Type.ToString() == "Number") 
+0

Non sono sicuro se hai omesso qualcosa, ma [ColumnHeader] (http://msdn.microsoft.com/en-us/library/system.windows .forms.columnheader.aspx) non ha una proprietà 'Type'. – Nick

0
class ListViewAutoSorter : System.Collections.IComparer 
{ 
    private int Column = 0; 
    private System.Windows.Forms.SortOrder Order = SortOrder.Ascending; 

    public ListViewAutoSorter(int Column, SortOrder Order) 
    { 
     this.Column = Column; 
     this.Order = Order; 
    } 

    public int Compare(object x, object y) // IComparer Member 
    { 
     if (!(x is ListViewItem)) 
      return (0); 
     if (!(y is ListViewItem)) 
      return (0); 

     var l1 = (ListViewItem)x; 
     var l2 = (ListViewItem)y; 

     var value1 = 0.0; 
     var value2 = 0.0; 

     if (Double.TryParse(l1.SubItems[Column].Text, out value1) && 
      Double.TryParse(l2.SubItems[Column].Text, out value2)) 
     { 
      if (Order == SortOrder.Ascending) 
      { 
       return value1.CompareTo(value2); 
      } 
      else 
      { 
       return value2.CompareTo(value1); 
      } 
     } 
     else 
     { 
      var str1 = l1.SubItems[Column].Text; 
      var str2 = l2.SubItems[Column].Text; 

      if (Order == SortOrder.Ascending) 
      { 
       return str1.CompareTo(str2); 
      } 
      else 
      { 
       return str2.CompareTo(str1); 
      } 
     } 
    } 
} 
Problemi correlati