2016-01-22 81 views
10

Ho un modulo Windows con un datagridview.Rende ordinabili tutte le colonne datagridview

La situazione ideale: scatta

utente su uno dei nove colonne, e il programma ordina tutti i dati, se la colonna cliccato contiene i numeri, vorrei che il numero più basso in alto. Se la colonna cliccata contiene una stringa, vorrei che fosse ordinata alfabeticamente (A-Z).

Quello che ho in questo momento:

ho visto una vecchia questione su Stack Overflow in cui il PO come ordinare la datagridview quando si fa clic "a" colpo di testa. La differenza con la mia è che voglio che il mio datagridview sia ordinabile da una qualsiasi delle nove colonne.

ho questo codice, rubato alla domanda che ho trovato:

dataGridView2.DataSource = listPlayers.Select(s => new { voornaam = s.Voornaam, 
                 Achternaam = s.Achternaam, 
                 positie = s.Positie, 
                 Nationaltieit = s.Nationaliteit, 
                 Leeftijd = s.Age, 
                 Aanval = s.Aanval, 
                 Verdediging = s.Verdediging, 
                 Gemiddeld = s.Gemiddeld, 
                 waarde = s.TransferWaarde }) 
            .OrderBy(s => s.Achternaam) 
            .ToList(); 

foreach(DataGridViewColumn column in dataGridView2.Columns) 
    { 
     dataGridView2.Columns[column.Name].SortMode = 
            DataGridViewColumnSortMode.Automatic; 
    } 

In questo modo solo l'ordine utente "Achternaam" quando fa clic su uno dei nove colonne. Quello che voglio è quando l'utente fa clic sulla colonna Nationaliteit, i dati vengono ordinati con l'An in cima. E così via per ogni colonna

Questa è la lista listplayers:

namespace SimulatorSimulator 
{ 
    class SpelerData 
    { 
     public string Voornaam { get; set; } 
     public string Achternaam { get; set; } 
     public string Positie { get; set; } 
     public string Nationaliteit { get; set; } 
     public int Age { get; set; } 
     public int Aanval { get; set; } 
     public int Verdediging { get; set; } 
     public int Gemiddeld { get; set; } 
     public string TransferWaarde { get; set; } 
    } 
} 

e nella classe principale:

List<SpelerData> listPlayers = new List<SpelerData>(); 

Alcuni dati fittizi:

Romelu;Lukaku;Aanvaller;Belgie;22;87;12;50;41.000.000,00  
Raheem ;Sterling;Aanvaller;Engeland;21;84;30;57;35.000.000,00  
Zlatan ;Ibrahimovic;Aanvaller;Zweden;34;87;21;54;34.500.000,00 
+0

@KevinTinnemans Si prega di considerare il commento di Ivan Stoev sulla risposta di Ian con più attenzione. Potrei essere fiammeggiato per averlo detto, e questo potrebbe essere frainteso da quando ho postato la mia risposta, ma la risposta accettata non ti aiuterà a diventare uno sviluppatore migliore in alcun modo. La forza bruta è un punto di partenza, ed è ciò a cui si ricade quando non si riesce a trovare una soluzione migliore, per la quale ce ne sono diversi per questo particolare problema. Ciò porterà a cattive pratiche e codice ingestibile. –

risposta

5

penso che il modo più semplice per il vostro caso sarebbe quella di mettere il backup dei dati in una tabella Database. In questo modo, puoi semplicemente utilizzare questo come data source per il tuo dataGridView2 e sarai in grado di eseguire facilmente l'ordinamento facendo clic sulla colonna dell'intestazione.

Un modo alternativo sarà utilizzare SortableBindingList (article) come suggerito anche dall'altra risposta.

Ma se entrambe le opzioni non sono tra le tue scelte, il modo più semplice a cui potrei pensare è creare un evento da ColumnHeaderMouseClick, e quindi puoi elencare il tuo ordinamento di conseguenza facendo uso di e.ColumnIndex e "mappatura" a destra (Dizionario) al vostro preparato IEnumerable<SpelerData>

Così, nel vostro carico della forma, si fa qualcosa di simile:

Dictionary<int, IEnumerable<SpelerData>> queryDict = new Dictionary<int, IEnumerable<SpelerData>>(); //Prepare a dictionary of query 
private void form_load(object sender, EventArgs e) { 
    dataGridView2.DataSource = listPlayers.OrderBy(x => x.Achternaam).ToList(); 
    queryDict.Add(0, listPlayers.OrderBy(x => x.Voornaam)); 
    queryDict.Add(1, listPlayers.OrderBy(x => x.Achternaam)); 
    queryDict.Add(2, listPlayers.OrderBy(x => x.Positie)); 
    queryDict.Add(3, listPlayers.OrderBy(x => x.Nationaliteit)); 
    queryDict.Add(4, listPlayers.OrderBy(x => x.Age)); 
    queryDict.Add(5, listPlayers.OrderBy(x => x.Aanval)); 
    queryDict.Add(6, listPlayers.OrderBy(x => x.Verdediging)); 
    queryDict.Add(7, listPlayers.OrderBy(x => x.Gemiddeld)); 
    queryDict.Add(8, listPlayers.OrderBy(x => x.TransferWaarde)); 
} 

E poi in caso ColumnHeaderMouseClick, fare semplicemente:

private void dataGridView2_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e) { 
    dataGridView2.DataSource = queryDict[e.ColumnIndex].ToList(); 
} 

E otterrai il comportamento che desideri.

Si noti che dal momento che IEnumerable è in ritardo di esecuzione, la preparazione anticipata dello Dictionary non avrà alcun impatto sulle prestazioni. L'unica cosa che devi aggiungere sono le 9 righe di codice nel form_Load per preparare il dizionario e 1 riga di codice nell'evento dataGridView2_ColumnHeaderMouseClick. Questa è la soluzione più semplice a parte i due che ho menzionato prima, a cui potrei pensare.

+1

* "Questa è la soluzione più semplice a parte le due che ho menzionato in precedenza e che potrei pensare." * Sebbene funzioni per il caso specifico, è più una soluzione che una soluzione. Cosa succede se hai bisogno dello stesso per un'altra griglia - ancora altre 10 righe di codice? Terza griglia ecc.? Anche la riassegnazione della fonte dei dati è altamente inefficiente e ha effetti collaterali. Le interfacce 'IBindingList' e' IBindingListView' sono create appositamente per gestire questo e altri scenari simili. La creazione di una classe generica di base potrebbe sembrare più codifica, ma vale la pena perché è uno sforzo di una volta e può essere riutilizzata in migliaia di luoghi. –

4

si potrebbe usare a SortableBindingList

SortableBindingList<T> list = new SortableBindingList<T>(); 

//Add items to list 

dataGridView.DataSource = list ; 

Ciò consentirà l'ordinamento cliccando sull'intestazione della colonna

public class SortableBindingList<T> : BindingList<T> 
{ 
    private readonly Dictionary<Type, PropertyComparer<T>> comparers; 
    private bool isSorted; 
    private ListSortDirection listSortDirection; 
    private PropertyDescriptor propertyDescriptor; 

    public SortableBindingList() 
     : base(new List<T>()) 
    { 
     this.comparers = new Dictionary<Type, PropertyComparer<T>>(); 
    } 

    public SortableBindingList(IEnumerable<T> enumeration) 
     : base(new List<T>(enumeration)) 
    { 
     this.comparers = new Dictionary<Type, PropertyComparer<T>>(); 
    } 

    protected override bool SupportsSortingCore 
    { 
     get { return true; } 
    } 

    protected override bool IsSortedCore 
    { 
     get { return this.isSorted; } 
    } 

    protected override PropertyDescriptor SortPropertyCore 
    { 
     get { return this.propertyDescriptor; } 
    } 

    protected override ListSortDirection SortDirectionCore 
    { 
     get { return this.listSortDirection; } 
    } 

    protected override bool SupportsSearchingCore 
    { 
     get { return true; } 
    } 

    protected override void ApplySortCore(PropertyDescriptor property, ListSortDirection direction) 
    { 
     List<T> itemsList = (List<T>)this.Items; 

     Type propertyType = property.PropertyType; 
     PropertyComparer<T> comparer; 
     if (!this.comparers.TryGetValue(propertyType, out comparer)) 
     { 
      comparer = new PropertyComparer<T>(property, direction); 
      this.comparers.Add(propertyType, comparer); 
     } 

     comparer.SetPropertyAndDirection(property, direction); 
     itemsList.Sort(comparer); 

     this.propertyDescriptor = property; 
     this.listSortDirection = direction; 
     this.isSorted = true; 

     this.OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1)); 
    } 

    protected override void RemoveSortCore() 
    { 
     this.isSorted = false; 
     this.propertyDescriptor = base.SortPropertyCore; 
     this.listSortDirection = base.SortDirectionCore; 

     this.OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1)); 
    } 

    protected override int FindCore(PropertyDescriptor property, object key) 
    { 
     int count = this.Count; 
     for (int i = 0; i < count; ++i) 
     { 
      T element = this[i]; 
      if (property.GetValue(element).Equals(key)) 
      { 
       return i; 
      } 
     } 

     return -1; 
    } 
} 
1

Se si è disposti a utilizzare la riflessione, è possibile fare qualcosa di simile al seguente.

NOTA: Suppongo che stiate usando lo DataGridView.ColumnHeaderMouseClick Event, ma questo non cambia il nucleo di questo approccio. Il punto è che è necessario identificare dinamicamente il valore di stringa che rappresenta il nome della colonna che si desidera OrderBy. Potresti codificare questa associazione se davvero hai bisogno/voluto.

private void dataGridView2_ColumnHeaderMouseClick(
    object sender, DataGridViewCellMouseEventArgs e) 
{ 
    ... 
    var sortCol = dataGridView2.Columns[e.ColumnIndex]; 
    var colName = sortCol.Name; 

    dataGridView2.DataSource = listPlayers.Select(s => new { voornaam = s.Voornaam, Achternaam = s.Achternaam, positie = s.Positie, Nationaltieit = s.Nationaliteit, Leeftijd = s.Age, Aanval = s.Aanval, Verdediging = s.Verdediging, Gemiddeld = s.Gemiddeld, waarde = s.TransferWaarde }) 
              .OrderBy(s => typeof(SpelerData).GetProperty(colName)) 
              .ToList(); 
    ... 
}