Newsgroup: it.comp.lang.visual-basic
Titolo: [vb.net] Modifica di dato in hashtable

Mi sembrava d'aver scritto il codice corretto per modificare un dato già 
inserito in una hashtable, ma in un'altra elaborazione (per la stampa) 
non mi prende il dato modificato.
Il principio base su cui ho lavorato è che è preferibile cancellare del 
tutto il dato e poi reinserirlo di nuovo piuttosto che verificare quali 
dati sono stati modificati e cambiare solo quelli: è corretto come 
principio, dovrei lavorare sulla modifica od è indifferente?
Christian

 Mi sembrava d'aver scritto il codice corretto...
Che non ci hai mostrato...
-- 
Gianluca Cannalire
Microsoft MVP/MCP - Visual Basic
http://www.visual-basic.it
http://community.visual-basic.it/gianluca

 Che non ci hai mostrato...
Lo faccio subito (semplifico il codice):
Public Class Class1
  Private _ID As Integer
  Private _C1 As String
Public Sub New (ByVal c1 As String)
  _C1 = c1
  _ID = _Contatore
   _Contatore += 1
End Sub
Public ReadOnly Property id() As Integer
   Get
      Return _ID
   End Get
End Property
Public Property C1() As String
   Get
      Return _C1
   End Get
   Set(ByVal Value As String)
      _C1 = Value
   End Set
End Property
End Class
'nel modulo
Public Hash As New Hashtable
'per inserire un nuovo record
Dim CC As New Class1 (textbox1.Text)
Hash.Add(CC.id, CC)
'per modificare un record esistente
Hash.Remove(a)   'a viene presa da SelectedIndexChanged
Dim CC As New Class1 (textbox1.Text)
Hash.Add(a, CC)
'ciclo for per stampare i dati
For i = 1 To Hash.Count
   Dim Record As CC = CType (Hash(i-1), CC)
...          'riche di codice di stampa che non dà problemi
End For
Quando stampo i dati senza modifiche non danno problemi, quando invece 
modifico un dato la variabile "Record" non si riempie correttamente.
Christian

Hash.Add(a, CC)
Cos'è 'a'?


 Cos'č 'a'?
'a' č una variabile che rappresenta la selezione dell'utente di una 
listview. Ho creato un evento listview1_SelectedIndexChanged che cattura 
il record selezionato dall'utente ed aggiorna la variabile. In questo 
modo so quale record l'utente vuole modificare e cosě facendo 'a' 
rappresenta anche la chiave della Hashtable. Una volta che conosco la 
chiave posso modificare/cancellare tutti i dati relativi.
Christian

 'a' è una variabile
di che tipo?
come la valorizzi?
Insomma, va bene non postare l'intero codice, ma almeno quel minimo per 
capire... che diamine!


 capire... che diamine!
Scusa, non avevo capito, provvedo subito:
Public a As String     'nel modulo
Private Sub ListView1_SelectedIndexCollection...
a=""
Dim Indici As ListView1.SelectedIndexCollection = 
Me.listview1.SelectedIndices
Dim Indice As Integer
For Each Indice In Indici
   a += String.Intern(Me.listView1.Items(Indice).Index())
Next
End Sub

 End Sub
Non stai scherzando, vero??? :)
Ma hai provato a vedere cosa c'è in 'a', prima di passarla al metodo 
remove dell'hashtable????


 remove dell'hashtable????
Non sto scherzando, il mio codice è proprio così.
Ho rifatto il debug per sicurezza inserendo 4 record, selezionando il 
terzo in 'a' vedo "2", come è giusto che sia.
Come mai sei così meravigliato?
Christian

 Come mai sei così meravigliato?
Prova a ragionare sul tuo codice, e capirai il perchè...
Ciao


 Prova a ragionare sul tuo codice, e capirai il perchè...
Ci ho ragionato parecchio tempo fa per crearlo, sinceramente non capisco 
cosa ci sia che non vada, a me sembra che sia tutto a posto.
Mi piacerebbe sapere cosa c'è che non va (ed anche il ragionamento che 
c'è dietro per non rifare l'errore) e se questo influisce sul codice 
postato prima.
Christian

 postato prima.
Iniziamo:
Public Sub New (ByVal c1 As String)
  _C1 = c1
  _ID = _Contatore
   _Contatore += 1
End Sub
Assumo che _Contatore sia un field shared (anche in virtù di un precedente 
thread) e che inizialmente il suo valore sia 0 (visto che non è 
specificato da alcuna parte)
Poi:
Private Sub ListView1_SelectedIndexCollection...
a=""
Dim Indici As ListView1.SelectedIndexCollection =
Me.listview1.SelectedIndices
Dim Indice As Integer
For Each Indice In Indici
   a += String.Intern(Me.listView1.Items(Indice).Index())
Next
End Sub
Innanzitutto, se la proprietà ID di Class1 è un Integer, perchè utilizzi 
una String per rimuoverla dall'hashtable?
Comunque, a parte le conversioni implicite, la seguente riga...
Hash.Remove(a)
...funziona _solo_ se c'è un singolo ListItem selezionato, altrimenti, nel 
caso di più ListItem, con questa concatenazione...
For Each Indice In Indici
   a += String.Intern(Me.listView1.Items(Indice).Index())
Next
...non saprei proprio cosa riusciresti a rimuovere dall'hashtable :)
(o aggiungere)
Proseguiamo:
Dim CC As New Class1 (textbox1.Text)
Hash.Add(a, CC)
Qui combini un pastrocchio :)
CC.ID
 avrà sicuramente un valore che è diverso dal valore di corrente di 
'a' (semprechè _Contatore sia shared, come supposto all'inizio)
Pertanto, qui non hai più la corrispondenza (key hastable)= 
CC.ID
 
dell'istanza Class1 associata
Infine:
For i = 1 To Hash.Count
   Dim Record As CC = CType (Hash(i-1), CC)
...          'riche di codice di stampa che non dà problemi
End For
Assumi che le key degli oggetti inseriti nell'hastable abbiamo un valore 
(e quindi un id) compreso (e sequenziale) tra 0 e Hash.Count - 1
Tra l'altro, è più corretto e leggibile scrivere
For i = 0 To Hash.Count -1
   Dim Record As CC = CType (Hash(i), CC)
    ...
End For
Però, non è detto che all'interno dell'hashtable, visto come gestisci gli 
"indici", non ci siano oggetti che hanno una key con un valore al di fuori 
di 0 e Hash.Count -1 o che non ci siano oggetti con un indice compreso tra 
0 eHash.Count -1.
Insomma, qualche dritta l'hai ricevuto... per il resto, datti da fare ;)


 Insomma, qualche dritta l'hai ricevuto... per il resto, datti da fare ;)
Ti ringrazio del tuo interessamento, ma se vorrai dedicarmi ancora un pò 
del tuo tempo non hai ancora affrontato il problema iniziale. Ovviamente 
a te servivano delle informazioni che per me sono scontate, hai fatto 
bene a chiedere ed io ti ho detto quanto chiedevi, se avessi altri dubbi 
non esitare a dirlo.
Vorrei rimarcare il problema iniziale.
'per inserire un nuovo record: funziona
Dim CC As New Class1 (textbox1.Text)
Hash.Add(CC.id, CC)
'per modificare un record esistente: sembra funzionare
Hash.Remove(a)
Dim CC As New Class1 (textbox1.Text)
Hash.Add(a, CC)
'ciclo for per stampare i dati
For i = 0 To Hash.Count - 1
   Dim Record As Class1 = CType (Hash(i), Class1)
...          'righe di codice di stampa che non danno problemi
End For
Ricordo che quando stampo i dati senza modifiche non dà problemi, quando 
invece modifico un dato la variabile "Record" non si popola.
Christian

 immaginabili prima di dichiarare completato il programma.
Beh, non lamentiamoci poi se i programmi hanno dei comportamenti anomali 
:)


 :)
Nel mio caso il valore č perfettamente uguale, ma l'anomalia rimane, 
quindi il problema č da ricercarsi da altre parti, o no?
Christian

(dedicato a Gianluca, ma chiunque può intervenire)
C'è chi dorme col pensiero di Monica Bellucci, chi col pensiero di 
Manuela Arcuri (o Brad Pitt per le donne, o metteteci voi un nome a 
caso), invece io ieri notte ho dormito col pensiero di come cavolo 
risolvevo il problema oggetto di questo thread (si, sono malato di 
visual basic, ognuno ha il proprio punto debole, il mio è questo).
Ebbene, mi è venuta l'ispirazione, stamattina l'ho applicata ed ora il 
problema della modifica è risolto. Spiego, ma prima un piccolo 
riassunto:
'per inserire un nuovo record
Dim CC As New Class1 (textbox1.Text)
Hash.Add(CC.id, CC)
'per modificare un record esistente
Hash.Remove(a)   'a viene presa da SelectedIndexChanged
Dim CC As New Class1 (textbox1.Text)
Hash.Add(a, CC)
Ora mi son detto: se funziona per un nuovo record, come mai non funziona 
per un record esistente? Allora ho modificato la Class1 per fare in modo 
che l'ultima riga della modifica sia:
Hash.Add(CC.id, CC)
quindi uguale all'inserimento del nuovo record.
La modifica principale a Class1 è sostanzialmente questa:
_ID = a
esatto, proprio una stupidaggine.
Riepilogando: poichè CC.id ed 'a' sono e saranno sempre uguali 
(garantito e certificato da me, fidatevi) invece di mettere 'a' nel 
caricamento dell'hashtable, ho caricato 'a' nell'id dentro la hashtable.
La mia domanda è: PERCHÉ ORA FUNZIONA E PRIMA NO????? (scusate l'urlo).
Io non sono uno che si accontenta di vedere che le cose funzionano, 
voglio anche capire perchè.
Grazie in anticipo a chi mi risponderà.
Christian
P.S.: una certa idea ce l'ho, ma non sono certo che sia per quel motivo 
e per non "inquinare" i vostri giudizi ve la dico dopo.    ;-)

Dimenticavo: manca ancora da risolvere il problema della cancellazione 
del dato dalla listview, ma insisto a studiare ed a provare finchè 
funzionerà.   ;-)
Christian

 motivo e per non "inquinare" i vostri giudizi ve la dico dopo.    ;-)
Senti, dato che non ho la più pallida idea di chissà quali altre cose hai 
scritto in quel codice, ce la fai a mandarmi il progetto zippato per 
email???
Ciao


 email???
Devo ammettere che sono molto meravigliato di questa tua richiesta, ma 
la trovo una cosa interessante e non vedo perchè non farlo.
Ho due progetti che porto avanti contemporaneamente, ma ti manderò 
quello in cui sono più avanti.
In quale e-mail te lo mando?
Poi se riesci a risolvere anche il problema che ho indicato nel mio 
messaggio del 28/03, ore 14.55 (nella parte finale, relativa alla 
cancellazione) te ne sarò riconoscente.
Christian

 cancellazione) te ne sarò riconoscente.
Tu prepara il progetto (mi raccomando, zippalo), poi vediamo che si può 
fare.


 fare.
Spedito.
Christian

 Spedito.
Ciao Christian,
ho finalmente avuto modo di dare un'occhiata al tuo codice...
Permettimi, ma dopo aver visto l'intero progettino, ribadisco il fatto che 
prima di metterti davanti al PC, hai bisogno di leggere (e bene) qualche 
libro sulla programmazione...
Comunque, veniamo al tuo specifico problema che, tralasciando tutto il 
resto del programma, e in questa porzione di codice:
(non ho aggiunto/rimosso nulla di quanto tu hai scritto: mi sono limitato 
ad aggiungere qualche commento)
Private Sub btnElimina_Click(ByVal sender As System.Object, ByVal e As 
System.EventArgs) Handles btnElimina.Click
'CHRISTIAN: questo codice non funziona come dovrebbe
'GLUCA: queste sono 2 var Int32 definite Public in un modulo
'in Selexlv hai l'indice del ListViewItem correntemente selezionato
Selexlv2 = Selexlv
'GLUCA: qui rimuovi (correttamente) l'oggetto 'Class1' dall'hashtable 
(ContattoHash)
'anch'essa globale
ContattoHash.Remove(Selexlv2)
'GLUCA: Premetto che Contattolv è un Array (dichiato con Public 
Contattolv() As ListViewItem)
'di oggetti ListViewItem
'Il metodo Remove che pertanto stai tentando di invocare non lo stai 
invocando sull'Array, bensì
'sul ListViewItem correntemente selezionato con l'indice Selexlv2
'Pertanto, non stai rimuovendo quel particolare ListViewItem dall'array
Contattolv(Selexlv2).Remove()
'GLUCA: Questa riga è completamente inutile
Contattolv(Selexlv2).SubItems.Clear()
'GLUCA: anche questa è inutile se successivamente invochi Items.Clear
lvwContatto.Items.RemoveAt(Selexlv2)
'GLUCA: qui, "correttamente", cancelli tutta la ListView e la ripopoli
'passando l'array di oggetti ListViewItem
lvwContatto.Items.Clear()
lvwContatto.Items.AddRange(Contattolv)
End Sub
A questo punto, ti ho dato la dritta che ti serve per rimuovere il "bug": 
lascio a te il compito di trovare la soluzione.
Tieni conto che per mantenere una collection di oggetti 'Class1', stai 
utilizzando contemporaneamente:
- Una hashtable
- Un array di ListViewItem
- Una collection di ListViewItem (quella "intrinseca" della ListView)
Insomma, come puoi ben capire, hai sbagliato approccio al problema...
P.S. Piccolo aiutino: cancella tutto il codice relativo all'array, e cerca 
di risolvere esclusivamente con l'HashTable. Ti è più che sufficiente
P.P.S. altro piccolo aiutino:
For i As Integer = 0 To ContattoHash.Count - 1
Dim lvi As New ListViewItem
Dim C As ContattoClass
C = CType(ContattoHash(i), ContattoClass)
lvi.Text = C.TipoContatto
lvi.SubItems(1).Text = C.Cognome
'...
'...
lvwContatto.Items.Add(lvi)
Next


 ...
Ho il pc dove ho installato vb in riparazione, quindi esaminerò le tue 
indicazioni solo quando mi ritornerà, in ogni caso grazie per il tuo 
interessamento.
Christian

 Next
Se ho capito bene questa porzione di codice dovrebbe andare a 
sostituire:
lvwContatto.Items.AddRange(Contattolv)
Il problema č che alla riga:
lvi.Text = C.TipoContatto
mi dą errore "Riferimento ad un oggetto non impostato su un'istanza di 
oggetto".
Come risolvere questo errore?
Christian

 Come risolvere questo errore?
Probabilmente, nell'hashtable, non hai nessun oggetto valido associato 
alla particolare key (indice) che stai utilizzando.


 alla particolare key (indice) che stai utilizzando.
Ho verificato e non è così, perchè con la riga:
C = CType(ContattoHash(i), ContattoClass)
si riempie bene C.TipoContatto (io userò C.id, ma non cambia il 
concetto).
Ho provato anche ad inserire un valore non dipendente da hashtable, 
tipo:
lvi.Text = "aaa"
ma mi dà lo stesso errore.
Christian

 ma mi dà lo stesso errore.
A questo punto devi aver modificato il codice rispetto a quello che ti ho 
suggerito io.
L'errore "Riferimento ad un oggetto non impostato su un'istanza di di 
oggetto" sta ad indicare che stai tentando di accedere ad un oggetto senza 
che lo stesso sia stato istanziato.
Pertanto, mostra il pezzo di codice così come lo hai modificato te.


 Pertanto, mostra il pezzo di codice così come lo hai modificato te.
Questo è il codice dell'evento incriminato:
    Private Sub mnuImpostaContatto_Click(ByVal sender As System.Object, 
ByVal e As System.EventArgs) Handles mnuImpostaContatto.Click
        Frmmod = False
        Dim frmImpostaContatto As New frmImpostaContatto
        frmImpostaContatto.ShowDialog()
        lvwContatto.Items.Clear()
        For i As Integer = 0 To ContattoHash.Count - 1
            Dim Record As ContattoClass = CType(ContattoHash(i), 
ContattoClass)
            lvi.Text = CStr(Record.ID)
            lvi.SubItems(Record.id).Text = Record.TipoContatto
            lvi.SubItems(Record.id).Text = Record.Scelta
            lvi.SubItems(Record.id).Text = Record.Nick
            lvi.SubItems(Record.id).Text = Record.Nome
            lvi.SubItems(Record.id).Text = Record.Mail
            lvwContatto.Items.Add(lvi)
        Next
Mi dà l'errore in questo punto:
            lvi.Text = CStr(Record.ID)
In fase di esecuzione del programma col debug attivo ho visto che 
Record.ID viene regolarmente riempito, quindi non capisco perchè mi dia 
quell'errore.
Christian

            lvi.Text = CStr(Record.ID)
Chissà come mai :))))
Perchè non provi a riguarda il MIO esempio, per capire qual'è la RIGA che 
ti sei dimenticato di COPIARE????


 che ti sei dimenticato di COPIARE????
"copiare"?
 BROGLIO ! BROGLIO!
:>

 BROGLIO ! BROGLIO!
ROTFL


 ti sei dimenticato di COPIARE????
Questa intendi?
Dim lvi As New ListViewItem
L'ho messa nel modulo come: 
Public lvi As ListViewItem
Mi sono dimenticato il New.    :-(((
Ecco l'errore d'istanza.
Adesso non dà più quell'errore, ma sono sorti due problemini:
1) se inserisco almeno due record, ho visto che in fase di debug al 
secondo ciclo for a questa riga:
lvi.SubItems(Record.id).Text = Record.TipoContatto
mi dà errore "Argomento specificato non compreso nell'intervallo" quando 
va a leggere nell'hashtable di Record.TipoContatto
2) se inserisco 1 solo record non dà errori, ma nella ListView non 
mostra nulla. Nella prima riga però è presente una riga, anche se i 
campi sono vuoti, e facendo doppio click vedo il form d'inserimento dati 
con i dati corretti, e tutto funziona anche se correggo questi dati. 
Però nella ListView vedo solo una riga vuota.
Christian

 Adesso non dà più quell'errore, ma sono sorti due problemini:
Non possiamo proseguire all'infinito con questo "debugging remoto".
Tanto per cominciare, metti quella riga di codice dove deve stare, e vedi 
se riesci a risolvere un po' da solo...
Ciao


 se riesci a risolvere un po' da solo...
Mica sono uno che attende senza fare nulla, leggi qui sotto per 
crederci.
Ho messo "Dim lvi As ListViewItem" dentro al ciclo "for" ma i due 
problemi citati prima non sono stati risolti.
Lavorandoci, ho provato risolvere questo problema:
1) se inserisco almeno due record, ho visto che in fase di debug al 
secondo ciclo for a questa riga:
lvi.SubItems(Record.id).Text = Record.TipoContatto
mi dà errore "Argomento specificato non compreso nell'intervallo" quando 
va a leggere nell'hashtable di Record.TipoContatto
togliendo questo codice (da te consigliatomi):
lvi.Text = CStr(Record.id)
lvi.SubItems(Record.id).Text = Record.TipoContatto
lvi.SubItems(Record.id).Text = Record.Scelta
lvi.SubItems(Record.id).Text = Record.Nick
lvi.SubItems(Record.id).Text = Record.Nome
lvi.SubItems(Record.id).Text = Record.Mail
lvwContatto.Items.Add(lvi)
ed inserendo questo codice:
lvwContatto.Items.Add(CStr(Record.id))
lvi.SubItems.Add(Record.TipoContatto)
lvi.SubItems.Add(Record.Scelta)
lvi.SubItems.Add(Record.Nick)
lvi.SubItems.Add(Record.Nome)
lvi.SubItems.Add(Record.Mail)
Dalle prime prove sembra che il problema sia risolto, però mi piacerebbe 
sapere perchè (a prima vista il tuo codice sembra sbagliato, almeno nel 
caso in questione, è possibile?????).
Il problema del secondo punto non sono riuscito a risolverlo:
2) dopo l'inserimento (mettiamo di una riga) nella ListView non vedo 


 sbagliato, almeno nel caso in questione, è possibile?????).
Fidati: se c'è qualcosa di sbagliato, non è il mio codice :)))


 Fidati: se c'è qualcosa di sbagliato, non è il mio codice :)))
Io mi fido, ma dammi un segno.    ;-)
Se volevi la dimostrazione che non sto senza far niente mi sembra 
d'averlo fatto.
Non dico che non voglio implementare il tuo codice, ci mancherebbe, ma 
se hai idea del motivo per cui non funziona sono tutt'orecchi.
Christian

> lvwContatto.Items.Add(lvi)
Ok, te lo mostro meglio:
lvi.Text = C.TipoContatto
lvi.SubItems(1).Text = C.Cognome
lvi.SubItems(2).Text = C.AltroCampo1...
lvi.SubItems(3).Text = C.AltroCampo2...
Capito?


 Capito?
Numeri le subitems...
Io finora ho sempre inserito i dati da visualizzare nelle subitems in 
ordine di visualizzazione...
Ho implementato la tua indicazione, ma si ferma qui:
lvi.SubItems(1).Text = C.Cognome
indicando come errore "...ArgumentOutOfRangeException...argomento 
specificato non compreso nell'intervallo".
Ho provato a scrivere 0 invece di 1, e va avanti, fermandosi alla 
seconda subitems.
Sembra che accetti soltanto lo 0 (o 
record.id
, che sarebbe sempre 0, 
visto che è il primo record inserito)...
Christian

 visto che è il primo record inserito)...
A questo punto, Christian, occorre che tu capisca bene come funziona una 
ListView e le sue collection di ListViewIteme SubItem.
Trovi tutto nella documentazione.
Ciao


 Trovi tutto nella documentazione.
In tutta la documentazione in mio possesso (sia on-line che a casa, e 
non è poca) non ho trovato un solo esempio od una sola descrizione che 
spieghi l'indice dell'elemento nell'insieme da recuperare:
lvi.Subitems(1).text........
É un peccato, perchè ti ho anche mandato il programmino e speravo che il 
problema si potesse risolvere.
Ti chiedo una cortesia: di rimandarmi la versione che ti ho mandato 
perchè nel frattempo ho fatto numerose aggiunte, miglioramenti e 
modifiche e non mi trovo su un particolare aspetto del programma, 
grazie.
Christian

 grazie.
Non l'ho più. L'ho cancellata dopo averti mandato uno dei tanti post.


 E' una Collection... lo vuoi capire???
Ecchecazz...
Tu si che sei paziente con la gente. Vabbè che è Pasqua, ma io l'avrei 
mandato a fare... una ricerca su google gia dal secondo/terz post :)
bye

 mandato a fare... una ricerca su google gia dal secondo/terz post :)
perche', il prim a chi l'avev assegnat? :)
si', gianluca ha una pazienza veramente impensabile.
si sara' fatto il callo coi prodotti ms :P
ciao e buona pasqua a tutti, a.
ps - ho dovuto rispondere fuori thread perche' 
individual.net
 non lasciava 
inviare, dicendo "line 3 too long". era la riga dei riferimenti dei 
messaggi...


Wow, ho ricercato il thread sepolto dai nuovi post e mi sarebbe stato comodo 
un monitor 32'' wide screen :)
Comunque Gianluca è un po' sibillino nelle risposte: non può mica pretendere 
che tutti capiscano cosa vuole dire se non lo dice ;)
Ciao 

 pretendere che tutti capiscano cosa vuole dire se non lo dice ;)
e' vero anche questo. non si capisce davvero perche' faccia tante storie e 
non posti esattamente vbp frm frx e possibilmente anche vbw, e dalla via 
anche l'exe debuggato, ovviamente coi dati gia' inseriti :)
ciao, a.

Nicola Ottomano says...

Già fatta tempo fa, ma non ho trovato nulla che mi fosse utile.
Christian

 Non l'ho più. L'ho cancellata dopo averti mandato uno dei tanti post.
Magari è ancora nel cestino...
In ogni caso grazie per la tua disponibilità.
Christian

 pretendere che tutti capiscano cosa vuole dire se non lo dice ;)
Sono stato così criptico??? :)
Eppure, gli indizi, ci son tutti...
Se poi il codice lo devo scrivere tutto io, beh, ditelo :))))
Ciao!
