Questo sito utilizza cookies, anche di terze parti, per mostrare pubblicità e servizi in linea con il tuo account. Leggi l'informativa sui cookies.
Username: Password: oppure
C# / VB.NET - Ordinamento di una listview in base al valore di una colonna
Forum - C# / VB.NET - Ordinamento di una listview in base al valore di una colonna

Avatar
alip1 (Normal User)
Pro


Messaggi: 84
Iscritto: 12/08/2019

Segnala al moderatore
Postato alle 19:16
Lunedì, 28/06/2021
Buon sera.
Scusatemi forse vi sto sottoponendo un problema forse già da voi risolto e ripetitivo chiedo venia.
Volevo provare ad ordinare una listview in base ai valori di due colonne: la prima colonna contiene l'ID (numeri) la seconda delle stringhe (campo Oggetto).
Cliccando sulla testata della colonna, provo ad ordinare in base alla colonna.

A tal fine mi sono servito dell'ottima guida Cap. 66 sulla ListView che ho trovato qui tra le guide su VB.NET.
Ho provato a realizzare quando suggerito utilizzando tra l'altro questi snippet di codice:
Codice sorgente - presumibilmente VB.NET

  1. Private Sub SortListViewItems(ByVal List As ListView, ByVal Comparer As IComparer(Of ListViewItem))
  2.  
  3.     Dim Occurrences As Int32 = 0
  4.  
  5.     Do
  6.             Occurrences = 0
  7.             For I As Int32 = 0 To List.Items.Count - 1
  8.                   If I = List.Items.Count - 1 Then
  9.                           Continue For
  10.                   End If
  11.                   If Comparer.Compare(List.Items(I), List.Items(I + 1)) = 1 Then
  12.                          SwapInList(List, I)
  13.                         Occurrences += 1
  14.                    End If
  15.             Next
  16.      Loop Until Occurrences = 0
  17. End Sub


ma mi sembra che non esca mai dal loop perché Occurrences é sempre =2. Non riesco a trovare l'errore. Provato su una listview con 6 item ma non va.
Inoltre nella routine di swap:
Codice sorgente - presumibilmente VB.NET

  1. Private Sub SwapInList(ByVal List As ListView, ByVal Index As Int32)
  2.  
  3.       Dim Temp As ListViewItem = List.Items(Index + 1)
  4.  
  5.       List.Items.RemoveAt(Index + 1)
  6.       List.Items.Insert IGNORE((Index, Temp))
  7.  
  8.    End Sub


l'istruzione
Codice sorgente - presumibilmente Plain Text

  1. List.Items.Insert IGNORE((Index, Temp))

sembra errata mi viene segnalata IGNORE per cui ho provato a toglierlo e scriverla così
Codice sorgente - presumibilmente Plain Text

  1. List.Items.Insert(Index, Temp)


Qualcuno potrebbe aiutarmi? Grazie

Ultima modifica effettuata da alip1 il 28/06/2021 alle 19:26
PM Quote
Avatar
Carlo (Member)
Guru


Messaggi: 972
Iscritto: 29/01/2018

Segnala al moderatore
Postato alle 22:07
Lunedì, 28/06/2021
Per ordinare qualsiasi colonna in una listview cliccandola è sufficiente una riga di codice.
La prima parte dell'esempio popola con dei dati a caso una listview che devi aggiungere sul form.
La listview non deve avere il sorting automatico della prima colonna, pena un loop di riordinamento (vedi riga 5).
Codice sorgente - presumibilmente VB.NET

  1. Public Class Form1
  2.     Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
  3.         '************ CODICE INUTILE, SOLO PER RIEMPIRE LA LISTVIEW ***************
  4.         ListView1.View = View.Details
  5.         ListView1.Sorting = SortOrder.None
  6.         ListView1.GridLines = True
  7.         ListView1.FullRowSelect = True
  8.         ListView1.Scrollable = True
  9.         ListView1.Columns.Add("ID") ' prima colonna
  10.         ListView1.Columns(0).Width = 40 ' la colonna ID 40 pix
  11.         For c = 0 To 9
  12.             ListView1.Columns.Add("colonna" & c + 1) ' nome della colonna
  13.             ListView1.Columns(c + 1).Width = 64 ' larghezza colonna
  14.         Next c
  15.         Dim rnd As New Random
  16.         For i = 0 To 10
  17.             ListView1.Items.Add(i.ToString("00"))
  18.             ListView1.Items(i).SubItems.Add(rnd.Next(1, 10) & "Casa")
  19.             ListView1.Items(i).SubItems.Add(rnd.Next(1, 10) & "test")
  20.             ListView1.Items(i).SubItems.Add(rnd.Next(1, 10) & "rnd")
  21.             ListView1.Items(i).SubItems.Add(rnd.Next(1, 10) & "dati")
  22.             ListView1.Items(i).SubItems.Add(Convert.ToChar(rnd.Next(65, 90)) & Convert.ToChar(rnd.Next(65, 90)))
  23.             ListView1.Items(i).SubItems.Add(Convert.ToChar(rnd.Next(65, 90)) & Convert.ToChar(rnd.Next(65, 90)))
  24.             ListView1.Items(i).SubItems.Add(Convert.ToChar(rnd.Next(65, 90)) & Convert.ToChar(rnd.Next(65, 90)))
  25.             ListView1.Items(i).SubItems.Add(Convert.ToChar(rnd.Next(65, 90)) & Convert.ToChar(rnd.Next(65, 90)))
  26.             ListView1.Items(i).SubItems.Add(Convert.ToChar(rnd.Next(97, 122)) & Convert.ToChar(rnd.Next(65, 90)))
  27.             ListView1.Items(i).SubItems.Add(Convert.ToChar(rnd.Next(97, 122)) & Convert.ToChar(rnd.Next(65, 90)))
  28.             ListView1.Items(i).SubItems.Add(Convert.ToChar(rnd.Next(97, 122)) & Convert.ToChar(rnd.Next(65, 90)))
  29.             ListView1.Items(i).SubItems.Add(Convert.ToChar(rnd.Next(97, 122)) & Convert.ToChar(rnd.Next(65, 90)))
  30.         Next
  31.         '***************************************************************************
  32.     End Sub
  33.  
  34.  
  35.     Private Sub ListView1_ColumnClick(ByVal sender As Object, ByVal e As ColumnClickEventArgs) Handles ListView1.ColumnClick
  36.         ' ***************** riga di codice che riordina al click ******************
  37.         Dim tmp() As ListViewItem = ListView1.Items.Cast(Of ListViewItem)().OrderBy(Function(t) t.SubItems(e.Column).Text).ToArray()
  38.         '***************************************************************************        
  39.         ListView1.BeginUpdate() ' sospendo il refresh della listview
  40.         ListView1.Items.Clear() ' cancello la listview
  41.         ListView1.Items.AddRange(tmp) ' la riscrivo completamente con i parametri ordinati
  42.         ListView1.EndUpdate() ' fine aggiornamento, la listview può essere visualizzata
  43.     End Sub
  44. End Class


Ultima modifica effettuata da Carlo il 29/06/2021 alle 0:18


in programmazione tutto è permesso
PM Quote
Avatar
alip1 (Normal User)
Pro


Messaggi: 84
Iscritto: 12/08/2019

Segnala al moderatore
Postato alle 9:00
Mercoledì, 30/06/2021
Grazie Carlo quindi nell'esempio della guida a cui ho fatto riferimento la routine di ordinamento:
Codice sorgente - presumibilmente C# / VB.NET

  1. SortListViewItems(ByVal List As ListView, ByVal Comparer As IComparer(Of ListViewItem))

non serve.
Inoltre nella tua routine la
Codice sorgente - presumibilmente Plain Text

  1. functionf(t)

a chi si riferisce??
Grazie e scusami

PM Quote
Avatar
Carlo (Member)
Guru


Messaggi: 972
Iscritto: 29/01/2018

Segnala al moderatore
Postato alle 10:45
Mercoledì, 30/06/2021
Per ordinare ho usato Linq.
Non è l'unico sistema, si possono usare molteplici approci, come IComparer ma anche altri.
Linq, va studiato per padroneggiarlo, funcion(t) è una dichiarazione
la riga:
Dim tmp() As ListViewItem = ListView1.Items.Cast(Of ListViewItem)().OrderBy(Function(t) t.SubItems(e.Column).Text).ToArray()

significa: dichiaro una matrice di oggetti ListViewItem
enumero applicando la conversione di tipo (cast) usando la funzione Linq OrderBy(Function(t) tutte le righe secondo l'ordine dei testi (Text) contenuti nella colonna cliccata (t.SubItems(e.Column)) in un array (tmp())

Perché ti ho proposto Linq, che richiede ulteriore studio per essere compreso?
Perché una listview con 8 colonne e 20000 righe viene riordinata istantaneamente con Linq, se invece esegui i cicli tu, compari e swappi da codice, no.

Invece non ho analizzato il tuo codice che sicuramente si può far funzionare, per problemi di tempo, l'esempio che ti ho postato l'avevo scritto qualche tempo fa e messo da parte quando studiavo.

Ultima modifica effettuata da Carlo il 30/06/2021 alle 10:55


in programmazione tutto è permesso
PM Quote
Avatar
alip1 (Normal User)
Pro


Messaggi: 84
Iscritto: 12/08/2019

Segnala al moderatore
Postato alle 12:43
Mercoledì, 30/06/2021
Grazie Carlo gentilissimo come sempre ho capito.
Un'ultima domanda L'istruzione è indipendente se si tratta di un Campo ID numerico o un campo di tipo Data??
Grazie

PM Quote
Avatar
alip1 (Normal User)
Pro


Messaggi: 84
Iscritto: 12/08/2019

Segnala al moderatore
Postato alle 12:48
Mercoledì, 30/06/2021
Grazie Carlo gentilissimo come sempre ho capito.
Non sapendo come fare in effetti pensavo di usare anche facendo una query tipo linq ma poi, come dicevo, mi sono rifatto all'esempio pubblicato nella guida su vb.net del sito, solo che non funzionava perchè non avevo messo
Codice sorgente - presumibilmente Plain Text

  1. LVTutte.Sorting = SortOrder.None

come suggerito da te.
Due ultime domande:
1) l'istruzione da te suggerita  è indipendente se si tratta di un Campo ID numerico o un campo di tipo Data??
2) una listview quante righe può contenere??
Grazie

PM Quote
Avatar
Carlo (Member)
Guru


Messaggi: 972
Iscritto: 29/01/2018

Segnala al moderatore
Postato alle 13:46
Mercoledì, 30/06/2021
Testo quotato

Postato originariamente da alip1:
1) l'istruzione da te suggerita  è indipendente se si tratta di un Campo ID numerico o un campo di tipo Data??


L'istruzione esegue un riordinamento alfabetico case insensitive, per ordinare i numeri è sufficiente visualizzarli con gli zeri all'inizio, come vedi nell'esempio sulla colonna ID.
Per un ordinamento mirato sul contenuto delle colonne, devi aggiungere una scelta in base alla colonna cliccata e al suo contenuto.
Per esempio se la colonna che contiene delle date è la numero1:
Codice sorgente - presumibilmente VB.NET

  1. Dim tmp() As ListViewItem
  2. If e.Column = 1 Then
  3.         tmp = ListView1.Items.Cast(Of ListViewItem)().OrderBy(Function(t) Convert.ToDateTime(t.SubItems(e.Column).Text)).ToArray()
  4. Else
  5.         tmp = ListView1.Items.Cast(Of ListViewItem)().OrderBy(Function(t) t.SubItems(e.Column).Text).ToArray()
  6. End If



Testo quotato

Postato originariamente da alip1:
2) una listview quante righe può contenere??



Vado a memoria, se compili a 32bit c'è un limite 65536 ? (sempre se la memoria è sufficiente in base alle colonne)
se compili a 64bit, il limite è dato dalla memoria disponibile.
Ma per sicurezza controlla.

Aggiungo che una listview con un numero elevato di righe/colonne, diventa ingestibile, e la sua visualizzazione può richiedere del tempo.
Una soluzione è tenere i dati in matrici, liste, tuple, in RAM, e caricare dinamicamente nella listview solo la parte visibile al momento.

Ultima modifica effettuata da Carlo il 30/06/2021 alle 14:17


in programmazione tutto è permesso
PM Quote
Avatar
alip1 (Normal User)
Pro


Messaggi: 84
Iscritto: 12/08/2019

Segnala al moderatore
Postato alle 11:58
Lunedì, 05/07/2021
Grazie Carlo

PM Quote