2009-07-31 22 views

Respuesta

19

Así es como pude clasificar en varias columnas y poder ordenar cada columna como un número o como texto.

primer lugar el uso de esta clase:

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

En el constructor de su formulario, establezca el clasificador de la siguiente manera:

lvSeries.ListViewItemSorter = new Sorter(); 

Entonces manejar la ColumnClick incluso de su control listview así:

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

Todo esto depende de que la propiedad Etiqueta de cada columna se establezca en "Num eric "o no, por lo que el clasificador sabe cómo ordenar.

En el ejemplo anterior eché los valores como flotantes cuando son numéricos, es posible que desee cambiar eso a int.

+1

@Neil: los clasifica como texto de forma predeterminada. P.ej. 100 viene antes de 3. Sin embargo, puede ordenar int correctamente con ListViewItemSorter personalizado. –

+0

Ahh, eso es correcto. cadena es el tipo predeterminado. –

+0

Seguí el ejemplo en http://support.microsoft.com/kb/319401 pero todavía no ordena los enteros correctamente. Texto implícito, ¿cómo configurar la columna predeterminada para ordenar? Funciona muy bien en la columna 1, pero no puedo encontrar la propiedad para que la columna pueda ordenar. – Brad

0

que había hágalo en la fuente de datos (modelo) en lugar de la vista. Ordenarlo allí y debe actualizarlo en la vista a través de enlace de datos.

+0

¿Quiere decir ordenar la datasouce, datatable en mi instancia, y luego volver a cargar la vista de lista cuando se haga clic en una columna? – Brad

+0

no, mala práctica para volver a cargar cada vez. Google "ListViewItemSorter" y le mostrará cómo ordenar por cada columna. –

+0

sí, eso es lo que pensé. – Brad

3

Deberá crear una clase que implemente la interfaz IComparer (la no genérica). En esa clase que lea la propiedad Text desde el sub-elemento, convertirlo a INT, y hacer la comparación:

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

continuación, se asigna un comparador como a la propiedad ListViewItemSorter e invocar el método de ordenación de la ListView Control:

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

algunas columnas son numéricas, otras son texto ... ¿debería hacer una prueba numérica antes de ordenar? – Brad

+1

Una vez hice un comparador ListViewItem que examinó cada elemento par en el método Compare, pero esto se volvió bastante lento. Será mejor que tenga comparadores separados y elija cuál usar según la columna que se está ordenando, o creando una clase comparer donde le pase un valor al constructor que indique si para hacer una clasificación basada en números, fechas o texto, y luego cambiar en el método Comparar en función de ese valor (que fue la solución que busqué en ese caso). –

+0

Buena idea. Pero creé una variable privada como 'sortType' dentro de mi listview compara cla ss en cambio. – Chris

5

Si va a empezar con un ListView, su vida será mucho más fácil si se utiliza un ObjectListView lugar. ObjectListView es un contenedor de código abierto alrededor de .NET WinForms ListView, y resuelve todos estos pequeños problemas molestos que normalmente hacen que trabajar con un ListView sea tan frustrante. Por ejemplo, ordena automáticamente los enteros de modo que '100' viene después de '3' (DateTimes, bools y todo lo demás también se ordena correctamente).

En serio, nunca querrá volver a un ListView simple después de usar un ObjectListView.

Sí, soy el autor, pero eso no quiere decir que soy parcial ... Está bien, bueno, tal vez :) Mire here para las opiniones de otras personas.

+0

Gracias ... voy a darle una prueba de manejo en este momento – Brad

0

Utilicé la clase de Neil-N, pero cambié la declaración if para probar la propiedad Type en lugar de la propiedad Tag. Establecí cada columna en Número de tipo (en lugar de Texto) que tenía un valor entero. Sort funciona de maravilla.

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

No estoy seguro si omitió algo, pero [ColumnHeader] (http://msdn.microsoft.com/en-us/library/system.windows .forms.columnheader.aspx) no tiene una propiedad '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); 
      } 
     } 
    } 
} 
Cuestiones relacionadas