Italian [Risolto] Come usare IndexOf(...) in CustomListView?

XorAndOr

Active Member
Licensed User
Longtime User
Ciao a tutti
Ho questo codice esempio
B4X:
Private Ser As B4XSerializator
Private ListViewLog As ListView

'Con la ListView ok funziona

Dim obj As Object = Ser.ConvertBytesToObject(Buffer)'Seriale

If ListViewLog.Items.IndexOf(obj) = -1 Then
    ListViewLog.Items.Add(obj)
Else

End If

'*********************************************************

'Con la CLV.....?...nin so


Dim obj As Object = Ser.ConvertBytesToObject(Buffer)'Seriale

If Clv1......?

    Clv1.Add(PanelItem(ItemWidth, ItemHeight), obj)
Else

End If
In un progetto che utilizzo la ListView funziona tutto bene
Vorrei sostituire la ListView con la custom list view ma mi sono perso con il metodo IndexOf(...) che non trovo nella clv
Gentilmente mi dareste na mano a risolvere?
Grazie
 

William Lancee

Well-Known Member
Licensed User
Longtime User
I would add a Gloabal Map object to keep track of the values of items in the CLV.
Aggiungerei un oggetto Global Map per tenere traccia dei valori degli elementi nel CLV.

B4X:
Private itemInCLV As Map
itemInCLV.Initialize

'When adding an item also add it to the Map
'Quando aggiungi un elemento, aggiungilo anche alla mappa
itemInCLV.Put(Obj, True)

'Test if obj is in CLV
'Verifica se obj è in CLV
If itemInCLV.containsKey(Obj) then

End IF
 

LucaMs

Expert
Licensed User
Longtime User
(Per curiosità, che tipo di dati serializzi?)

Il suggerimento di @William Lancee potrebbe anche andare bene ma credo che abbia un paio di problemi:

1 - mantenere allineati la Map e la CLV
2 - non avresti un indice nella Map che corrisponda a quello della CLV.

Per il punto 2, potresti usare una List anziché una Map. Per il punto 1, anche con una List avresti la stessa scocciatura (se volessi spostare o eliminare un item della CLV, avresti problemi con la List).

Dato che non si dovrebbe avere una CLV con migliaia di item (sarebbe molto scomoda per l'utente, quindi pessima scelta architetturale) ma direi al massimo un centinaio, potresti semplicemente scorrere CLV per controllare se l'oggetto esista già, operazione che sarebbe più che sufficientemente veloce.
B4X:
    Dim Exists As Boolean ' False di default.
  
    For i = 0 To Clv1.Size - 1
        If Clv1.GetValue(i) = obj Then
            Exists = True
            Exit
        End If
    Next
  
    If Exists Then
    Else
    End If
 

William Lancee

Well-Known Member
Licensed User
Longtime User
Instead of a boolean, put the index.
As @LucaMs cautions, you need to be careful that you keep the Map synchronized.

Invece di un valore booleano, inserisci il file index.
Come avverte @LucaMs, devi stare attento a mantenere sincronizzata la mappa.

B4X:
    Dim obj As Object = CreateMap()        'just an example of some object
   
    Private itemInCLV As Map
    itemInCLV.Initialize

    'When adding an item also add it to the Map
 'When you add an item, add it to the map as well
    itemInCLV.Put(obj, CustomListView1.Size)

    'Test if obj is in CLV
    Log(itemInCLV.GetDefault(obj, -1))   '0 if not there then -1
 

XorAndOr

Active Member
Licensed User
Longtime User
Per curiosità, che tipo di dati serializzi?
Grazie per la risposta @LucaMs
I dati mi arrivano in Byte da un congegno elettronico nella porta seriale.

Onestamente prima di postare la domanda avevo provato con la list
perchè tempo fa mi avevi risolto un problema dei doppioni (nomi)
e ho visto che funzionava.
Il motivo del post è capire perchè con una semplice list esiste il metodo IndexOf
mentre con una CustomListView non è possibile fare la stessa cosa.
Oltre a trovare se c'è un metodo con magari una sola riga di codice, che non conosco per adattarlo.

Il codice di @William Lancee devo fare delle prove per verificare se tutto è
come prima con la listview.

Per eliminare l'item dalla clv uso. Pensi che và bene?
B4X:
For i = 0 To Clv1.Size -1
   Dim item As String = Clv1.GetValue(i)
   If item = Obj Then                          
       Clv1.RemoveAt(i)
       itemInCLV.Remove(item)' <<<<--aggiunto per rimuovere dalla map  /add for remove from map
       Return  
   End If
Next
 
Last edited:

William Lancee

Well-Known Member
Licensed User
Longtime User
NO, if you change the indices of items by removing one, you have to rebuild the index map, NOTE that Dim item As Object <===Important NOT String
As @LucaMs cautions, you need to be careful that you keep the Map synchronized.

B4X:
    Dim index As Int = itemInCLV.GetDefault(obj, -1)
    CustomListView1.RemoveAt(index)
    itemInCLV.Clear
    For i = 0 To CustomListView1.size - 1
        Dim item As Object = CustomListView1.GetValue(i)
        itemInCLV.Put(item, i)
    Next
 

LucaMs

Expert
Licensed User
Longtime User
NOTE that Dim item As Object <===Important NOT String
Quanto sopra è fondamentale: nessun metodo ipotizzato può funzionare SE stiamo parlando di oggetti.

A te, @XorAndOr, IndexOf di ListView funziona perché in realtà cerchi stringhe, NON oggetti.

Quando leggi il tuo oggetto:
Dim obj As Object = Ser.ConvertBytesToObject(Buffer)'Seriale
in realtà stai creando un NUOVO oggetto contenente alcuni dati (quelli del buffer).
Se lo cercassi nella CLV non lo troveresti mai, anche se PENSI d'averlo aggiunto in precedenza, perché in realtà quello aggiunto è un oggetto diverso rispetto a quello creato con Dim, benché contenga gli stessi dati.

Quando si fa il confronto:
If OggettoNellaCLV = obj (creato sopra, con Dim)
non vengono confrontati i contenuti dei due oggetti ma i loro "puntatori", riferimenti, che saranno sempre diversi.

Tutto quello si può fare, quando si tratti di oggetti, è scorrere gli item della CLV e confrontare il contenuto delle proprietà dei due oggetti.
Nel tuo caso si tratta di stringhe, quindi puoi effettuare la ricerca, sempre sequenzialmente, senza usare List o Map, ma devi dichiarare come String la variabile che conterrà quanto letto tramite la deserializzazione (e altrettanto, ovviamente, dovrai scrivere una stringa come valore degli item).

Il motivo del post è capire perchè con una semplice list esiste il metodo IndexOf
mentre con una CustomListView non è possibile fare la stessa cosa.
Il motivo è proprio quello sopra: gli item delle CLV hanno come valore associato degli oggetti, non delle stringhe.
 
Last edited:

XorAndOr

Active Member
Licensed User
Longtime User
Buongiorno
A te, in realtà cerchi stringhe, NON oggetti.
esatto
i miei "device" (congegni elettronici) hanno un ID-12345678 ecc...
che quando si collegano vanno a finire nella listview ma grazie a quel IndexOf non ho l'ID ripetuto
I device per andare nella listview li controllo con la variabile Dim Obj as Object che per forza la devo serializzare altrimenti non ho i dati corretti.
Avevo provato a mettere String anzichè Object, ma avevo risultati sbagliati.
I miei progetti elettronici funzionano bene sempre con questo metodo cioè Object invece di string.
Non ho approfondito il fatto se sono stringhe o object. Ho visto che con Object avevo la stringa come mi serviva e ho adottato lo stesso metodo.

Il codice sopra postato da Williams (Thanks) l'ho provato ma non mi convince molto (non che sia sbagliato il codice) ma ho delle cose inaspettate
cioè mi sdoppia i nomi degli ID-123467 ecc.. in arrivo. E poi quando li elimino dalla Clv fa confusione.
Ricordo che io non li elimino a mano dalla listview o Clv...avviene in automatico quando il device si disconnette (invia un comando).
Ricordo anche che con La ListView funziona tutto bene anche con 10 device che inviano il loro ID e si disconnettono in automatico.
(Sto anche pensando di lasciare perdere la Clv...ma....)

Grazie Luca della spiegazione sopra, ora mi è più chiaro.
 
Last edited:

LucaMs

Expert
Licensed User
Longtime User
tutto bene anche con 10 device che inviano il loro ID
Quindi si tratta di stringhe (ID) e da non molti device, probabilmente parecchi meno di 100, per cui puoi benissimo eseguire un ciclo sugli item per controllare se hai già inserito un certo ID, sarà molto veloce, non è indispensabile un IndexOf.

Non sono certo se avverrebbe automaticamente una conversione di tipo, se scrivessi:
B4X:
Dim DevID As String = Ser.ConvertBytesToObject(Buffer)'Seriale
anche se penso proprio di sì. Altrimenti:
B4X:
Dim objID As Object = Ser.ConvertBytesToObject(Buffer)'Seriale
Dim DevID As String = objID
e poi esegui la ricerca:
B4X:
    Dim Exists As Boolean ' False di default.
 
    For i = 0 To Clv1.Size - 1
        If Clv1.GetValue(i) = DevID Then
            Exists = True
            Exit
        End If
    Next
 
    If Exists Then
    Else
    End If
 

XorAndOr

Active Member
Licensed User
Longtime User
Oggi il forum và a tratti...non vedo le icone, solo caratteri confusi di code/code. Vabbè sta sistemando, ci sta.

Allora...ho lasciato Obj per evitare di modificare tutto il progetto
B4X:
Dim Obj As String = Ser.ConvertBytesToObject(Buffer)
provato con 4 device e me li aggiunge alla CLV senza problemi, sembra tutto ok
faccio altre provole con più device

gentilmente mi diresti come eliminare l'item (ID)
perchè con il mio codice...
B4X:
java.lang.IndexOutOfBoundsException: Index -1 out of bounds for length 2

poi un'altra cosa...è qui che và clv.add? vedo che li aggiunge...
B4X:
If Exists Then

Else
    Clv1.Add(PanelItem(ItemWidth, ItemHeight), Obj_In)
End If
 
Top