Oppure

Loading
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 7:00
alip1
Grazie Carlo quindi nell'esempio della guida a cui ho fatto riferimento la routine di ordinamento:
SortListViewItems(ByVal List As ListView, ByVal Comparer As IComparer(Of ListViewItem))
non serve.
Inoltre nella tua routine la
functionf(t)
a chi si riferisce??
Grazie e scusami
aaa
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 10:48
alip1
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
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
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
05/07/21 9:58
alip1
Grazie Carlo
aaa