2011-01-15 18 views
7

Una pregunta relativamente simple. Tengo una vista de tabla de datos, que todo lo que hace es mostrar estadísticas. No hay edición/adición/eliminación de filas. La vista de tabla de datos está vinculada a una lista. Todo lo que quiero lograr es que el usuario pueda ordenar las columnas.Ordenando datagridview datasource en la lista <T> donde T es anónimo

class Market 
{ 
    public int Location {get;set;} 
    public float Value {get;set;} 
    //... 
} 
class City 
{ 
    public String Name {get;set;} 
    //... 
} 

List<Market> _markets; 
List<City> _cities; 
//Lists are populated. 

dataGridView1.DataSource = _markets.Select(market => 
    new { _cities[market.Location].Name, market.Value}).ToList(); 

Como era de esperar, las columnas no son ordenables, pero la información que se muestra es lo que se busca. Mi pregunta es cómo hacer que la ordenación de DataGridView se base en el tipo de columna con la cantidad de código menos complicada y menor, ya que el código se usará varias veces en todo momento.

Esta aplicación solía usar una base de datos que tenía vistas. Estas vistas luego poblaron DataGridViews. Las vistas son todavía alrededor, por lo que una posible solución podría ser:

DataBase.ViewMarketValue temp = new DataBase.ViewMarketValue() 

_markets.ForEach(market => temp.AddViewMarketValueRow(_cities[market.Location].Name, market.Value); 
dataGridView1.DataSource = temp; 

Esto da lugar a la deseada: un DataGridView que tiene toda la información y que se puede ordenar. El único problema es que parece incorrecto usar vistas en este aspecto. ¿Entonces qué debo hacer?

Respuesta

10

Para poder ordenar los datos automáticamente en el DataGridView, necesita una colección que implemente IBindingListView. En el BCL, las únicas clases que implementan esta interfaz son DataView y BindingSource (pero esta última solo admite la ordenación si la fuente de datos subyacente también lo admite).

lo tanto, usted tiene varias opciones:

  • crear un DataTable para contener los datos, y se unen a la DataGridView (que en realidad se unirá al DefaultView del DataTable)
  • crear su propia colección clase que implementa IBindingListView
  • usa una implementación existente, como la clase AdvancedList<T> publicada por Marc Gravell en this post. También tendrá que añadir un constructor para crear la lista del resultado de su consulta:

    public AdvancedList(IEnumerable<T> collection) 
    { 
        foreach (var item in collection) 
        { 
         Add(item); 
        } 
    } 
    

Puesto que el resultado de la consulta es un tipo anónimo, usted no será capaz de llamar al constructor directamente. La forma más fácil de evitar el problema es aprovechar la inferencia de tipo, creando un método genérico que creará la lista. Para mayor comodidad, se puede crear como un método de extensión:

public static AdvancedList<T> ToAdvancedList<T>(this IEnumerable<T> source) 
{ 
    return new AdvancedList<T>(source); 
} 

A continuación, puede utilizarlo como esa:

dataGridView1.DataSource = _markets.Select(market => 
    new { _cities[market.Location].Name, market.Value}).ToAdvancedList(); 
+0

Muy buena solución! Mi única queja (y es pequeña) es que la clasificación no es tan rápida como ideal, pero es tolerable y lo mejor hasta ahora. –

+1

Es lento porque usa el reflejo para obtener el valor de la propiedad. Puede modificar fácilmente la clase PropertyComparer para que genere un delegado cuando se crea y utiliza este delegado en lugar de property.GetValue –

+0

@ThomasLevesque sería genial si pudiera publicar algún fragmento de código para implementar su sugerencia. Gracias – Esen

Cuestiones relacionadas