Newsgroup: it.comp.lang.visual-basic
Titolo: [vb.net] Aggiungere righe e valori a datagridview popolato con dataset

Dunque, al clik di un button si apre un form contenente soltato una 
datagridview e viene popolato con un dataset e formattato.
Il codice associato al click è il seguente:
FormTecnici = New Tecnici
FormTecnici.Show()
FormTecnici.DgViewTecnici.DataSource = objDataView_Tec
Formatta_DataGrid_Tecnici(FormTecnici.DgViewTecnici)
Il dataset è impostato su public.
Quello che vorrei fare ora è insere una ulteriore colonna che numeri 
progressivamente le righe.
Ho provato inserendo nell'evento load del FormTecnici (che contiene il 
datagridview) il seguente codice:
DgViewTecnici.Columns.Add("nprog", "n°")
DgViewTecnici.Columns("nprog").Width = 30
Dim i As Integer
For i = 1 To objDataSet_Tec.Tables("Tecnici").Rows.Count - 1
DgViewTecnici.Rows.Add()
DgViewTecnici.Rows(i).Cells("nprog").Value = i
Next
Ma il risultato non è quello sperato, ho soltanto aggiunto una colanna, 
denominata "n°" ma vuota.
Come posso risolvere?

 Come posso risolvere?
C'ho messo un po a risponderti perchè avevo impegni e volevo postarti
un esempio CONCRETO provato e funzionante!
VB.net 2008Express:
Form + Datagridview.
 Datagridview chiamata myGrid
Copia e incolla
Imports System.Data
Public Class Form1
    Dim MioDS As DataSet
    Dim MiaTab As DataTable
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
        CreaMetaDB()
        With MyGrid
            .DataSource = MioDS
            .DataMember = "TestTab"
            .AutoGenerateColumns = True
        End With
        'aggiunta colonna
        Dim MiaCol As New DataGridViewColumn
        MiaCol.HeaderText = "Contatore"
        MiaCol.Name = "Contatore"
        MiaCol.ValueType = System.Type.GetType("System.String")
         MiaCol.DefaultCellStyle.NullValue = "#"
        Dim defCella As New DataGridViewTextBoxCell
        MiaCol.CellTemplate = defCella
        MiaCol.ReadOnly = True
        MyGrid.Columns.Insert(0, MiaCol)
        'IMPORTANTE
        MyGrid.VirtualMode = True
    End Sub
    Public Sub CreaMetaDB()
        MioDS = New DataSet
        MiaTab = New DataTable
        Dim Riga As DataRow
        With MiaTab
            .TableName = "TestTab"
            .Columns.Add("Nome", System.Type.GetType("System.String"))
            .Columns.Add("Cognome", System.Type.GetType
("System.String"))
            Riga = .NewRow
            Riga("Nome") = "Pippo"
            Riga("Cognome") = "De pippis"
            .Rows.Add(Riga)
            Riga = .NewRow
            Riga("Nome") = "Paolino"
            Riga("Cognome") = "Paperino"
            .Rows.Add(Riga)
            Riga = .NewRow
            Riga("Nome") = "Mickey"
            Riga("Cognome") = "Mouse"
            .Rows.Add(Riga)
        End With
        MioDS.Tables.Add(MiaTab)
    End Sub
    Private Sub MyGrid_CellValueNeeded(ByVal sender As Object, ByVal e
As System.Windows.Forms.DataGridViewCellValueEventArgs) Handles
MyGrid.CellValueNeeded
        'qui generi il progressivo
        'es.
        If e.RowIndex >= 0 AndAlso e.ColumnIndex = Me.MyGrid.Columns
("Contatore").Index Then
            e.Value = "CVT" + CType(e.RowIndex + 1, String)
        End If
    End Sub
End Class
Alcune spiegazioni:
La griglia è BOUND la colonna UNBOUND
Per far scattare l'evento CellValueNeeded la griglia DEVE essere
VIRTUALMODE TRUE!
Per creare una colonna in pratica va definito tutto...hai il massimo
controllo ma anche la massima responsabilità!
Qui dichiari un ogegtto COLONNA DATAGRIDVIEW
        'aggiunta colonna
        Dim MiaCol As New DataGridViewColumn
Qui assegni alcune proprietà
        MiaCol.HeaderText = "Contatore"
        MiaCol.Name = "Contatore"
Qui il tipo di dato che raccoglie
        MiaCol.ValueType = System.Type.GetType("System.String")
Qui come comportarsi in caso di valori nulli...stampa un #!
         MiaCol.DefaultCellStyle.NullValue = "#"
Questo è IMPORTANTISSIMO...se non lo metti ti dà errore
in pratica devi comunicare che tipo di cella vuoi visualizzare
texbox è uno dei tanti...puoi mettere un command button...e anche
altro...sperimenta!
        Dim defCella As New DataGridViewTextBoxCell
        MiaCol.CellTemplate = defCella
LA riga è un progressivo no? e allora...sola lettura!
        MiaCol.ReadOnly = True
Ed adesso ta-dah!
inserisco la nuova colonna all'indice 0 ...ossia come prima colonna a
sinistra
        MyGrid.Columns.Insert(0, MiaCol)

         MiaCol.ReadOnly = True
...logico che al posto de "LA riga è un progressivo
no?"....intendevo....
"LA colonna è un progressivo no?"

 ha scritto nel messaggio 
news:80a592ea-d1c7-4a7e...@s1g2000prg.googlegroups.com...

Si...
Grazie per il codice... veramente esauriente. 

 ha scritto nel messaggio 
news:80a592ea-d1c7-4a7e...@s1g2000prg.googlegroups.com...

...quello che mi chiedevo è se è possibile aggiungere una colonna partendo 
da un dataset già esistente.
Te lo chiedo perchè se non ho capito male, dal tuo esempio, il dataset lo 
crei ex-novo, nel mio caso il dateset, forse l'ho detto troppo di sfuggita 
nel post iniziale, è già creato e dato da quanto segue:
Dim objDataAdapter_Tec As New OleDbDataAdapter( _
"SELECT * from Tecnici ORDER BY Tecnici.nominativo", objConnection)
'BY Prog", objConnection)
objDataSet_Tec = New DataSet()
objDataAdapter_Tec.Fill(objDataSet_Tec, "Tecnici")
objDataView_Tec = New DataView(objDataSet_Tec.Tables("Tecnici"))
...o forse, molto più probabilmente non ho ben capito io il meccanismo che 
hai descritto... 

 zac
Calma e gesso!..mi sà che c'è un po di confusione e che alcuni
concetti li devi un po chiarire!
Io ho creato un dataset e una datatable...perchè non sapevo come le
popolavi....
Il dataset se ne frega di come è riempito....alla fine avrai un
ogggetto contenitore (il dataset) e gli oggetti contenuti in esso (in
questo caso DataTable)
Se colleghi un database...alla fine avrai la stessa situazione....con
in più in mezzo un dataAdapter!
Quindi avrai ...il database....il dataAdapter che COLLEGA in db ed
esegue dei comandi SQL per recuperare/inserire/aggiornare dati...ed il
dataset che a sua volta conterrà tante dataTable a seconda di quanti
dataAdapter colleghi o di quante query esegui!
Sul dataset/dataTable....esegui operazioni che poi ...NON si
riflettono automaticamente sul DB....ma devono OBBLIGATORIAMENTE
passare (se lo usi) per il dataAdapter....solo lui conosce i comand
SQL per aggiornare il db.
Quindi COME io ho inserito una colonna in QUEL dataset..lo stesso fai
nel tuo caso.....
metti uno STOP nel codice appena visualizzi i dati nella form (al
limite un command con dentro solo STOP)
adesso cicca sulla finestra (o sula voce di menu se non hai aperta la
finestra) visualizza variabili locali....cerca il tuo dataset (presumo
sia objDataSet_Tec)....se vedi c'è una lente di ingrandimento...se ci
clicchi si apre un browser...dove vedrai le dataTable create....
Basta che tu sostituisca il nome della tua dataTable al mio
esempio....
cosa cambia? Nulla! Che tu lo crei al volo...o no il sistema per
aggiungere una colonna di conteggio ad una gridview è quello!
Ma forse tu vuoi aggiungere una colonna al dataset...anzi alla
datatable?
Beh cambia veramente poco....il concetto è sempre quello....
Aggiungi una colonna all'oggetto
Quindi pria dichiara un oggetto DataColumn...e poi aggiungilo alla
dataTable
una cosa del tipo...vado a memoria..
Dim miaCol As DataColumn
miaCol = New DataColumn("NomeColonna", System.Type.GetType
("System.String"))...o altri dati che vuoi inserire
System.Integer ...System.Long etc etc
e poi aggiungerla alla dataTable
NomeDataset.Tables("nome dataTable").Columns.add(miaCol)
Non sperare però che ti finisca nel database la modifica....per farlo
dovresti alterare anche le query SQL del dataAdapter...quelle dei
metodi cancella, inserisci, modifica,seleziona
Se tutto questo ambarandan è per aggiungere al database un campo
"codice" che ti sei dimenticato di inserire.....
inserisci il campo nella struttura delle tabelle e rielabora il
dataset aggiornando la query di selezione!
Quindi in sostanza
per numerare le righe della datagrid si fà com ti ho detto!
Se vuoi anche aggiungere campi calcolati....sempre come ho detto...(ad
esempio il prezzo finale: quantità per prezzo)
Se vuoi inserire colonne al dataset datatable....come ti ho detto qui
Se vuoi aggornare la struttura del database....o con gli strumenti del
database
o con il comando sql ALTER TABLE.....eseguito casomai da un oggetto
Command (da fare una sola volta) e poi aggiornando i vari command del
dataAdapter
SE
non ai capito nulla di quello che ho detto.....
libro di Balena...o di chi vuoi....
ristudia il capitolo ADO.net
Saluti!

 ha scritto nel messaggio 
news:1b8dfe11-bfd9-404a-8b0e-
<Calma e gesso!..mi sà che c'è un po di confusione e che alcuni
<concetti li devi un po chiarire!
Questo è sicuro.
<Io ho creato un dataset e una datatable...perchè non sapevo come le
<popolavi....
<Il dataset se ne frega di come è riempito....alla fine avrai un
<ogggetto contenitore (il dataset) e gli oggetti contenuti in esso (in
<questo caso DataTable)
Fin qui c'ero.
<Se colleghi un database...alla fine avrai la stessa situazione....con
<in più in mezzo un dataAdapter!
Ok, c'ero anche fin qui.
<Quindi avrai ...il database....il dataAdapter che COLLEGA in db ed
<esegue dei comandi SQL per recuperare/inserire/aggiornare dati...ed il
<dataset che a sua volta conterrà tante dataTable a seconda di quanti
<dataAdapter colleghi o di quante query esegui!
Perfetto.
<Sul dataset/dataTable....esegui operazioni che poi ...NON si
<riflettono automaticamente sul DB....ma devono OBBLIGATORIAMENTE
<passare (se lo usi) per il dataAdapter....solo lui conosce i comand
<SQL per aggiornare il db.
Ecco... qui non c'ero. Pensavo dove agire nel dataset e non passare per 
l'adapter...
<Quindi COME io ho inserito una colonna in QUEL dataset..lo stesso fai
<nel tuo caso.....
<metti uno STOP nel codice appena visualizzi i dati nella form (al
<limite un command con dentro solo STOP)
<adesso cicca sulla finestra (o sula voce di menu se non hai aperta la
<finestra) visualizza variabili locali....cerca il tuo dataset (presumo
<sia objDataSet_Tec)....se vedi c'è una lente di ingrandimento...se ci
<clicchi si apre un browser...dove vedrai le dataTable create....
<
<Basta che tu sostituisca il nome della tua dataTable al mio
<esempio....
<cosa cambia? Nulla! Che tu lo crei al volo...o no il sistema per
<aggiungere una colonna di conteggio ad una gridview è quello!
<
<Ma forse tu vuoi aggiungere una colonna al dataset...anzi alla
<datatable?
Esatto.
<Beh cambia veramente poco....il concetto è sempre quello....
<Aggiungi una colonna all'oggetto
<
<Quindi pria dichiara un oggetto DataColumn...e poi aggiungilo alla
<dataTable
<una cosa del tipo...vado a memoria..
<
<Dim miaCol As DataColumn
<miaCol = New DataColumn("NomeColonna", System.Type.GetType
<("System.String"))...o altri dati che vuoi inserire
<System.Integer ...System.Long etc etc
<
<e poi aggiungerla alla dataTable
<NomeDataset.Tables("nome dataTable").Columns.add(miaCol)
<
<Non sperare però che ti finisca nel database la modifica....per farlo
<dovresti alterare anche le query SQL del dataAdapter...quelle dei
<metodi cancella, inserisci, modifica,seleziona
No, infatti non voglio farlo. E' solo una modifica "estetica"...
<Se tutto questo ambarandan è per aggiungere al database un campo
<"codice" che ti sei dimenticato di inserire.....
<inserisci il campo nella struttura delle tabelle e rielabora il
<dataset aggiornando la query di selezione!
Voglio solo numerare progressivamente le righe del dataset che prende i dati 
dal db ma sono ordinati in ordine alfabetico...
<SE
<non ai capito nulla di quello che ho detto.....
Scherzi... ho capito un sacco di cose.
Grazie per la pazienza.
<libro di Balena...o di chi vuoi....
<ristudia il capitolo ADO.net
<
<Saluti!
Ciao. 

 ha scritto nel messaggio 
news:1b8dfe11-bfd9-404a-8b0e-
<Calma e gesso!..mi sà che c'è un po di confusione e che alcuni
<concetti li devi un po chiarire!
Ok, ho chiarito i concetti, ho provato il tuo codice, tutto ok.
L'ho adattato alla mia situazione, tutto ok! :-)
Grazie.
Soltanto una cosa.
Siccome dovrei usare questo metodo più volte volevo parametrizzare le 2 sub 
(l'aggiunta colonna e la generazione del progressivo).
Ho creato un modulo e le ho inserite. Ora devo passare loro dei parametri.
Nessun problema con la sub per l'aggiunta colonna, mentre per la sub 
sull'inserimento del num prog... ho qualche dubbio sul formato dei 
parametri...
Mi spiego, questa è la tua private sub:
Private Sub MyGrid_CellValueNeeded(ByVal sender As Object, ByVal e As 
System.Windows.Forms.DataGridViewCellValueEventArgs) Handles 
myGrid.CellValueNeeded
If e.RowIndex >= 0 AndAlso e.ColumnIndex = 
Me.myGrid.Columns("Contatore").Index Then
e.Value = "CVT" + CType(e.RowIndex + 1, String)
End If
End Sub
La trasformo in una sub ed ho la necessità, quando la richiamo, di passare: 
nome del form, nome del dgv etc...
Ho provato con:
InserisceNumProgressivo(ByVal f As System.Windows.Forms, ByVal 
DataGridViewName As DataGridView, ByVal e As 
System.Windows.Forms.DataGridViewCellValueEventArgs)
Ma sicuramente sto sbagliando perchè mi da errore qui:
f.DataGridViewName.Columns("nprog").Index Then indicando che 
DataGridViewName is not a member of System.Windows.Forms.Form.
Ti è rimasta un briciolo di pazienza per spiegarmi dove sbaglio?
Grazie in anticipo.

 Grazie in anticipo.
L'evento della grid......!!!
devi inserire il codice che genera un codice in quell'evento...ossia
CelleValueNeeded
http://msdn.microsoft.com/it-it/library/system.windows.forms.datagridview.cellvalueneeded(VS.80).aspx
In quell'evento chiede il valore delle celle....e lì puoi modificare!
NON DOVE PARE A TE!...è in quell'evento che hai quelle proprietà!
INOLTRE (al limite)
dovresti passare  byref non byval..
la differenza abbi pazienza...non me ne volere...non è da poco....e la
lascerei a te capire e studiare!
Io poi non parametrizzerei un bel cavolo nulla!
Se ho bisogno di un codice ...lo metto nella tabella perchè mi
serve...e non vedo problemi ad aggiungere un campo! Esistono anche i
codici ad uso interno che non si mostrano al cliente...sapessi quante
mie griglie hanno la colonna nascosta ma con dentro l'ID del record!
Se poi è SOLO estetica....lo faccio al volo in QUELLA griglia....sono
solo 3 righe di codice in un evento!
Faccio notare che una numerazione progressiva non ha bisogno di
sofisticazioni!
E' solo estetica!
se noti il mio esempio....se pippo ha codice CVT1...e cancelli
pippo....la griglia ricalcola il codice e CVT1 se lo prende Paperino
...con un comportamento così NON CI PUOI (giustamente) fare nulla da
codice! Sbaglieresti record tutte le volte che qualcuno inserisce o
cancella righe!
Ripeto...è solo per bellezza!!!
Inoltre comincia a pensarla anche in maniera meno vb6 e più dotnet
SPEZZA la tua applicazione
Un conto è la base dati e le regole per mantenere l'integrità dei dati
Un conto le REGOLE per maneggiare i dati
Un conto la presentazione dei dati
se spezzi la tua applicazione in 3 strati: Logica Database - Logica
Business - Logica Interfaccia....avrai già di per sè una applicazione
multi utente multi db e anche con un interfaccia modificabile a
seconda del dispositivo (una per Vista, Una per il web Una per il
Palmare, Una per lo smartphone)
Questi 3 strati devono essere il più possibile indipendenti
quindi
Fatti dare dal DB una datatable...mettila LOCALMENTE in un
dataset....MOSTRA il dataset con regole LOCALI in base al tuo
dispositivo di interfacciamento.
Se riesci a fare una struttura del genere...la tua app avrà
lunghissima vita...e vivrai più tranquillo come programmatore!
In conclusione:
decidi cosa vuoi....con chiarezza...se è solo ESTETICA (solo
interfaccia)...va bene quello che ti ho detto...localmente PER QUELLE
GRIGLIE che vuoi...intercetta quell'evento e costruisci al volo il tuo
codice!!!
Ciauz!

 ha scritto nel messaggio 
news:2f1cc048-bb27-4670-babd-
[cut]
Grazie per tutte le info e per la paziena...
hai ragione, forse ragiono troppo in vb6, ma non sono un programmato, sto 
sviluppando un'applicazione coi pochi ricordi che avevo di vb6 e che mi 
serve per lavoro, nient'altro.
<In conclusione:
<decidi cosa vuoi....con chiarezza...se è solo ESTETICA (solo
<interfaccia)...va bene quello che ti ho detto...localmente PER QUELLE
<GRIGLIE che vuoi...intercetta quell'evento e costruisci al volo il tuo
<codice!!!
Quello che mi hai detto va benissimo. Ed ho risolto il mio problema, 
parametrizzando la sub per l'aggiunta colonna e lasciando l'evento 
cellnededvalue così com'era...
Grazie.
Ti chiedo un ultima cosa (forse un pò OT ma evito di aprirci un altro post) 
che metterà a nudo tutta la mia ignoranza in materia... tanto ormai...
L'applicazione si basa su un db access.
Mi collego al db, definendo connection, adapter, dataset, dataview... etc.
Quello che non ho capito è: che differenza c'è nell'utilizzare un db come 
esposto sopra (con il db access, assolutamente separato dall'applicazione 
che però lo richiama, passa quelle query etc...) o nell'inglobarlo nel 
progetto come "(new) data source"?
Ad esempio, nel secondo caso, quando preparo il pacchetto per distribuire 
l'applicazione (devo passarla a qualche pc della lan) il db lo ingloba nella 
stessa o troverò sempre un file esterno database.mdb?
Ringrazio di nuovo e mi scuso se ti sto facendo perdere la pazienza di 
venerdì sera. :-)

 ha scritto nel messaggio
zac
In realtà non c'è nessuna differenza e c'è tutta!
Mi spiego...se usi un dataAdapter...lo devi fare specifico per il
database che colleghi
SqlServer ...ha l'sqlDataAdapter
Access...ha oledbDataAdapter
Oracle....e così via!
In realtà OLEDB va benissimo ....ma esistono driver dedicati e
ottimizzati per dotnet specializzati nel collegare i database
DataAdapter in realtà è esso stesso un contenitore di varia roba:
Hai una parte dedicata a "connettere" il database
una parte dedicata a "chiedere" al database via SQL dati o eseguire
comandi
una parte dedicata a prendere il risultato ed eventualemnte
restituirlo in forma di database
una parte che potrebbe risolvere i conflitti tra record etc etc
Tutta questa roba ...la puoi usare anche da te...."a mano"...facendo a
meno del dataAdapter. OledbConnection per connettersi OleDbCommand per
eseguire comandi etc etc...un buon manuale di 
vb.net
 alla sezione
ado.net
 ti saprà dare tutte le info del caso!
Il database....
parlare di logica DB in access è abbastanza "sui generis".
Access non ingloba backup, trigger e amenità varie!
Il massimo che puoi fare è memorizzare delle query parametriche e
richiamarle dall'esterno!
...le richiami con il dataAdapter o con un oggetto OleDbCommand
Quindi diciamo che la logica del DB....è limitata in access.
Diverso il discorso in MySQL o SQLserver....dova la limite puoi
spostare LI DENTRO tutta(o gran parte) la logica business!
SQLserver ha un linguaggio interno...trigger stored function...che di
fatto potrebbero inglobare gran parte della logica di funzionamento
del programma!
Potresti però fare una cosa intelligente....
lavorare in astrazione....
farti un tuo oggetto che espone dei dati "filtrati e recuperati":
Dataset o datatable.
Un oggetto svincolato da qualsiasi riferimento.
Potresti farti un oggetto che ha un metodo "AnagraficaClienti" e
ritorna una dataTable.
Ed un metodo "AggiornaAnagraficaClienti" dove accetta una dataTable e
ritorna true o false se l'aggiornamento del db è avvenuto con
successo.
Usi MySQL invece di Access....cambi la parte di questo oggetto che
colelga e gestisce le tue rischieste.
Es.
In access poterbbe essere "SELECT * FROM AnagraficaClienti"
in mysql potrebbe essere richiamare la stored procedure
"AnagraficaClienti"
Se fai SEMPRE COSI' la tua applicazione sarà "un pelino" più lenta ma
cambiare database ti costringe a cambiare solo le procedure di un
oggetto....non tutta l'applicazione!
Considerando poi che lavori OOP....potresti avere un ogegtto base e
derivare da quelo le implementazioni reali del database effettivamente
usato.
E in ultimo....ora esiste anche LINQ
Linq to sql
e
Linq to Entity
Con sopratutto Linq to Entity....sei ad un livello di astrazione
abbastanza elevato....
Non ci farai il programma che gestisce il call center della telecom
ma un programma multi utente per una piccola media azienda di sicuro
si!
Buono studio!
Notte notte!