28/06/21 17:16
alip1
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:
Private Sub SortListViewItems(ByVal List As ListView, ByVal Comparer As IComparer(Of ListViewItem))
Dim Occurrences As Int32 = 0
Do
Occurrences = 0
For I As Int32 = 0 To List.Items.Count - 1
If I = List.Items.Count - 1 Then
Continue For
End If
If Comparer.Compare(List.Items(I), List.Items(I + 1)) = 1 Then
SwapInList(List, I)
Occurrences += 1
End If
Next
Loop Until Occurrences = 0
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:
Private Sub SwapInList(ByVal List As ListView, ByVal Index As Int32)
Dim Temp As ListViewItem = List.Items(Index + 1)
List.Items.RemoveAt(Index + 1)
List.Items.Insert IGNORE((Index, Temp))
End Sub
l'istruzione
List.Items.Insert IGNORE((Index, Temp))
sembra errata mi viene segnalata IGNORE per cui ho provato a toglierlo e scriverla così
List.Items.Insert(Index, Temp)
Qualcuno potrebbe aiutarmi? Grazie
Ultima modifica effettuata da alip1 28/06/21 17:26
aaa
28/06/21 20:07
Carlo
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).
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'************ CODICE INUTILE, SOLO PER RIEMPIRE LA LISTVIEW ***************
ListView1.View = View.Details
ListView1.Sorting = SortOrder.None
ListView1.GridLines = True
ListView1.FullRowSelect = True
ListView1.Scrollable = True
ListView1.Columns.Add("ID") ' prima colonna
ListView1.Columns(0).Width = 40 ' la colonna ID 40 pix
For c = 0 To 9
ListView1.Columns.Add("colonna" & c + 1) ' nome della colonna
ListView1.Columns(c + 1).Width = 64 ' larghezza colonna
Next c
Dim rnd As New Random
For i = 0 To 10
ListView1.Items.Add(i.ToString("00"))
ListView1.Items(i).SubItems.Add(rnd.Next(1, 10) & "Casa")
ListView1.Items(i).SubItems.Add(rnd.Next(1, 10) & "test")
ListView1.Items(i).SubItems.Add(rnd.Next(1, 10) & "rnd")
ListView1.Items(i).SubItems.Add(rnd.Next(1, 10) & "dati")
ListView1.Items(i).SubItems.Add(Convert.ToChar(rnd.Next(65, 90)) & Convert.ToChar(rnd.Next(65, 90)))
ListView1.Items(i).SubItems.Add(Convert.ToChar(rnd.Next(65, 90)) & Convert.ToChar(rnd.Next(65, 90)))
ListView1.Items(i).SubItems.Add(Convert.ToChar(rnd.Next(65, 90)) & Convert.ToChar(rnd.Next(65, 90)))
ListView1.Items(i).SubItems.Add(Convert.ToChar(rnd.Next(65, 90)) & Convert.ToChar(rnd.Next(65, 90)))
ListView1.Items(i).SubItems.Add(Convert.ToChar(rnd.Next(97, 122)) & Convert.ToChar(rnd.Next(65, 90)))
ListView1.Items(i).SubItems.Add(Convert.ToChar(rnd.Next(97, 122)) & Convert.ToChar(rnd.Next(65, 90)))
ListView1.Items(i).SubItems.Add(Convert.ToChar(rnd.Next(97, 122)) & Convert.ToChar(rnd.Next(65, 90)))
ListView1.Items(i).SubItems.Add(Convert.ToChar(rnd.Next(97, 122)) & Convert.ToChar(rnd.Next(65, 90)))
Next
'***************************************************************************
End Sub
Private Sub ListView1_ColumnClick(ByVal sender As Object, ByVal e As ColumnClickEventArgs) Handles ListView1.ColumnClick
' ***************** riga di codice che riordina al click ******************
Dim tmp() As ListViewItem = ListView1.Items.Cast(Of ListViewItem)().OrderBy(Function(t) t.SubItems(e.Column).Text).ToArray()
'***************************************************************************
ListView1.BeginUpdate() ' sospendo il refresh della listview
ListView1.Items.Clear() ' cancello la listview
ListView1.Items.AddRange(tmp) ' la riscrivo completamente con i parametri ordinati
ListView1.EndUpdate() ' fine aggiornamento, la listview può essere visualizzata
End Sub
End Class
Ultima modifica effettuata da Carlo 28/06/21 22:18
in programmazione tutto è permesso
30/06/21 8:45
Carlo
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 30/06/21 8:55
in programmazione tutto è permesso
30/06/21 10:43
alip1
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
aaa
30/06/21 11:46
Carlo
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:
Dim tmp() As ListViewItem
If e.Column = 1 Then
tmp = ListView1.Items.Cast(Of ListViewItem)().OrderBy(Function(t) Convert.ToDateTime(t.SubItems(e.Column).Text)).ToArray()
Else
tmp = ListView1.Items.Cast(Of ListViewItem)().OrderBy(Function(t) t.SubItems(e.Column).Text).ToArray()
End If
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 30/06/21 12:17
in programmazione tutto è permesso