Ordinamento DataGridView

lunedì 06 novembre 2006 - 16.29

Abdujaparov Profilo | Newbie

Salve a tutti da giorni cerco di capire come fare per ordinare i dati di una DataGridView in base alla colonna.
Io ho un mio oggetto di una classe
public class ProcDescription : INotifyPropertyChanged

La classe le proprietà dei dati che voglio visualizzare e che costituiranno le mie colonne. Implementa l'intefaccia INotifyPropertyChanged per aggiornare la visualizzazione dei dati, a seguito di alcuni cambiamenti.

Poi ho creato questa classe:
public class ProcDesCollection : BindingList<ProcDescription>
{


}

Così completamente vuota, in pratica è una lista di ProcDescription (perchè eredito la classe BindingList<ProcDescription>.

Creo poi un oggetto ProcDescription, lo assegno al bindingsource che assegno al datagridview.

Ora per permettere l'ordinamento delle colonne con il click del tasto sinistro sull'header delle colonne (che sono le proprietà della classe ProcDescription), cosa devo fare?
Come devo implementarlo? Girando su internet non è che abbia capito molto, anche dal sito dell'msdn, sarà un mio limite e chiedo scusa, però purtroppo sono bloccato.
A quanto ho capito devo modificare la classe ProcDesCollection (che è completamente vuota, non un campo, non una proprietà non un metodo) ma come?
Grazie a tutti, ciao ciao.

freeteo Profilo | Guru

ciao,
la cosa è 1po complessa, ma non impossibile, e quest'ultima è sempre una buona notizia.
Quello che manca a te è sostanzialmente di "overridare" il metodo Sort ,quindi diciamo implementarlo, ma prima di fare questo devi "overridare" anche altre proprieta' per prenderti la proprieta' selezionata per ordinare e la direzione, ma la cosa piu' importante è dirgli che puo' essere ordinabile, ovvero SupportsSrotingCore.

Tante chiacchiere, meglio 1 esempietto chiarificatore:
public class SortableBindingList<T> : BindingList<T> { //---- prendo le proprieta' che mi serviranno poi per fare il mio ordinamento private ListSortDirection m_Direction = ListSortDirection.Ascending; private PropertyDescriptor m_SortProperty; protected override ListSortDirection SortDirectionCore { get { return m_Direction; } } protected override PropertyDescriptor SortPropertyCore { get { return m_SortProperty; } } //-- come vedi torna sempre true cosi' fai capire alla griglia che puo' ordinare la collezione protected override bool SupportsSortingCore { get { return true; } } //-- questo è il posto dove farai tu l'ordinamento, in base alle proprieta' protected override void ApplySortCore(PropertyDescriptor property, ListSortDirection direction) { List<T> items = this.Items as List<T>; if (items != null) { m_Direction = direction; m_SortProperty = property; items.Sort(new Comparison<T>(confronto)); } } //---- questo effettivcamente fa il confronto private int confronto(T obj1, T obj2) { int Ris = 0; Ris =((IComparable)m_SortProperty.GetValue(obj1)).CompareTo(m_SortProperty.GetValue(obj2)); if (m_Direction == ListSortDirection.Descending) Ris = -Ris; return Ris; } }
tipicamente io uso questo, ma stai attento che il confronto non tiene conto dei nulli e di altri strutture complesse, cmq penso che con questo esempio tu possa fare delle prove e delle raffinatezze in questa direzione e quindi riuscire tranquillamente...
ciao.

Matteo Raumer
[MCAD .net]
http://blogs.dotnethell.it/freeteo

Abdujaparov Profilo | Newbie

Ciao grazie mille, allora ho letto ed ho qualche dubbio:
1) La clacce SortableBindingList devo crearla ex novo? Oppure devo implementare qualche interfaccia nella mia ProcDesCollection?
2) L'argomento PropertyDescriptor devo passarlo io o viene in automatico passato dalla datagridview quando clicco sull'header?
3) Comparison<T> è un template predefinito della libreria o devo fare qualcosa io a mano?
Per quanta riguarda i confronti sono quasi tutti su stringhe eccetto qualche intero, questa istruzione:

Ris =((IComparable)m_SortProperty.GetValue(obj1)).CompareTo(m_SortProperty.GetValue(obj2));

come funziona? Come capisce se fare il confronto tra stringhe o intero? Devo implementarlo io verificando il nome della proprietà e quindi capire se devo confrontare numeri o stringhe?
Il nome della proprietà lo ottengo tramite m_SortProperty.Name o qualcosa di simile?
Grazie mille, sei preziosissimo.
Ciao ciao.

freeteo Profilo | Guru

>Ciao grazie mille, allora ho letto ed ho qualche dubbio:
>1) La clacce SortableBindingList devo crearla ex novo? Oppure devo implementare qualche interfaccia nella mia ProcDesCollection?
come vuoi, quello era 1pezzo di codice che uso io, per non farmi problemi di tipizzare troppo e quindi poterlo riciclare in varie applicazioni.
Dovresti usarlo pio o meno cosi':
SortableBindingList<ProcDescription> lst = new SortableBindingList<ProcDescription>(); ...riempi la lista... dataGridView1.DataSource = lst;
se invece nell'implementazione della sortablebindinglist vuoi fare a meno di usare il generic "T" (e quindi applicarlo per varie strutture/classi) e usare solo una determinata classe va bene lo stesso, solo che te lo sconsiglio altrimenti non puoi riciclare il codice (e quindi perde di valore), io ti consiglio di usarlo cosi' com'e', magari con qualche controllo di null e che sia icomparable per evitare problemi a runtime


>2) L'argomento PropertyDescriptor devo passarlo io o viene in automatico passato dalla datagridview quando clicco sull'header?
viene in automatico, è quello che scatena la griglia quando clicchi, ovviamente pero' si aspetta 1a struttura che lo supporti (come dataview e datatable)

>3) Comparison<T> è un template predefinito della libreria o devo fare qualcosa io a mano?
è una delegate che sfrutta generic, l'ho fatto cosi' per evitare di tipizzarmi ma non è obbligatori esattamente quello, l'importante è che faccia 1 confronto (e quindi punti ad una funzione che torni un int per intenderci)

>Per quanta riguarda i confronti sono quasi tutti su stringhe
>eccetto qualche intero, questa istruzione:
>
>Ris =((IComparable)m_SortProperty.GetValue(obj1)).CompareTo(m_SortProperty.GetValue(obj2));
>
>come funziona? Come capisce se fare il confronto tra stringhe
>o intero?
entrambi sono comparabili, quindi il problema non ce l'hai. Pero' potrebbe venirti fuori quando quella proprieta' è qualcosa che non implementa l'interfaccia "icomparable" (e quindi non implementa il metodo "compareTo"), ti basta controllarlo cmq...

>Devo implementarlo io verificando il nome della proprietà
>e quindi capire se devo confrontare numeri o stringhe?
lo fa gia, prendendo tramite reflection la proprieta' e il suo tipo

>Il nome della proprietà lo ottengo tramite m_SortProperty.Name
>o qualcosa di simile?
esatto, e te lo passa la griglia in automatico quando clicchi sull'intestazione della colonna, quindi se debugghi lo vedi tranquillamente

>Grazie mille, sei preziosissimo.
>Ciao ciao.
di niente, spero di esserti stato d'aiuto!


* anch'io penso che la griglia (o meglio "la collezione") potrebbe farlo direttamente da sola, senza dover usare questa struttura, tanto alla fine usa reflection per farlo e quindi potrebbe arrangiarsi come fanno datatable e dataview.
Probabilmente pero' ci sono problemi di qualche altro genere che al momento non conosco...confido in qualche update
ciao.

Matteo Raumer
[MCAD .net]
http://blogs.dotnethell.it/freeteo

Abdujaparov Profilo | Newbie

Ciao allora la tua classe così com'è ho provato ad utilizzarla ma dovrei cambiare troppe cose nel codice e quindi farei troppi danni, però ho provato a fare questa cosa bruttissima che sotto allego. Per compilare compila ma quando lancio il programma e clicco sull'header della colonna mi viene data questa eccezione:
"An unhandled exception of type 'System.NotSupportedException' occurred in System.dll

Additional information: Specified method is not supported."

E mi viene segnalato errore su questa riga:
Application.Run(new Form1());

quindi non riesco neanche a capire dove trovare l'errore nel codice che ho implementato.
Il mio codice è questo:
Il codice sorgente non è stato renderizzato qui
perchè non c'è sufficiente spazio.
Clicca qui per visualizzarlo in una nuova finestra


Quando compilo mi viene dato questo warning:
"...\AppDesCollection.cs(15,36): warning CS0649: Field 'Task.AppDesCollection.m_SortProperty' is never assigned to, and will always have its default value null"
Grazie, ciao ciao.

freeteo Profilo | Guru

ciao, ti sei dimenticato 1pezzo fondamentale:
Il codice sorgente non è stato renderizzato qui
perchè non c'è sufficiente spazio.
Clicca qui per visualizzarlo in una nuova finestra
"ApplySortCore" è proprio il metodo che la griglia chiama per farlo, se non lo metti lui quando lo chiama da errore, e si aspetta di chiamarlo perche' la proprieta' "SupportsSortingCore" appiunto restituisce true fisso (ecco perche te li ordina).

Altra cosa, questa classe deve essere la collezione degli elementi quindi devi implementare collectionBase o se usi quella che ti ho postato io, non hai problemi, usa generic quindi puoi usarla per fare la collezione delle tue classi senza cambiare codice.
Ti ripeto:

SortableBindingList<miaClasseQualsiasi> mialista = new SortableBindingList<miaClasseQualsiasi>();
e poi riempi la lista.
Alla griglia metti come datasource proprio questa collection e quindi quando la griglia chiama il metodo sort (ovvero "ApplySortCore") lui fa l'ordinamento usando la "confronto"....
ciao.

Matteo Raumer
[MCAD .net]
http://blogs.dotnethell.it/freeteo

Abdujaparov Profilo | Newbie

Ciao, ho aggiunto quel metodo e tutto ha iniziato a funzionare.
Ti ringrazio infinitamente.
La classe che ti ho postato (ed a cui ho aggiunto il metodo) è proprio una lista in pratica.
Grazie infinitamente, sei stato fondamentale.
Ciao ciao.

freeteo Profilo | Guru

bene,
se sei riuscito, accetta una risposta cosi' marchiamo il thread come risolto.grazie.
ciao.

Matteo Raumer
[MCAD .net]
http://blogs.dotnethell.it/freeteo
Partecipa anche tu! Registrati!
Hai bisogno di aiuto ?
Perchè non ti registri subito?

Dopo esserti registrato potrai chiedere
aiuto sul nostro Forum oppure aiutare gli altri

Consulta le Stanze disponibili.

Registrati ora !
Copyright © dotNetHell.it 2002-2024
Running on Windows Server 2008 R2 Standard, SQL Server 2012 & ASP.NET 3.5