Descrizione :
Una mia tecnica per gestire la Multi-Selezione utente su DataGridView.
+ Articolo :
Spesso nei Forum Tecnici capita di leggere richieste sull'utilizzo avanzato del Controllo DataGridView, sempre molto utile e adatto alla rappresentazione di dati in svariate situazioni.
In questo Articolo penso di dare una risposta pratica e abbastanza completa sul problema di riuscire a selezionare con il Mouse, ma non solo ( la tecnica seguente tiene conto anche della selezione via tastiera e via codice... ) i dati presenti in un DataGridView connesso ad un DataTable, mantenendo tale selezione attiva.
Non sono quindi necessarie colonne CheckBox aggiuntive nè combinazioni di tasti ( niente CTRL ) per eseguire le selezioni e inoltre le Righe o Celle selezionate vengono automaticamente raccolte in opportune List() di riferimento che rimangono sempre aggiornate e pronte al prelievo dei dati.
Per replicare l'esempio seguente basta predisporre la solita Application Windows Forms con una Form "FormMain".
Su FormMain servono 4 controlli. Nell'ordine da sinistra a destra sono :
--> DataGridView : DGV1.
--> ListBox : lst_dgv1.
--> DataGridView : DGV2.
--> ListBox : lst_dgv2.
- DGV1 rappresenta i dati del proprio DataSource ( DT1 ), e mostra la tecnica sulla selezione delle Rows.
Le Rows selezionate e raccolte nella propria List() "selectedRows", sono mostrate nella lst_dgv1.
- Analogamente, DGV2 rappresenta i dati del proprio DataSource ( DT2 ), e mostra la tecnica sulla selezione delle Cells.
Le Cells selezionate e raccolte nella propria List() "selectedCells", sono mostrate nella lst_dgv2.
Perciò le due ListBox qui hanno scopo di verifica costante e visibile di quanto avviene dietro le quinte.
Non occorre impostare alcuna proprietà dei controlli a design, in quanto tutto viene definito al Load().
La figura seguente mostra un esempio di utilizzo a runtime :
--> Codice FormMain :
Public Class FormMain 'DataTable per DGV1 Private DT1 As New DataTable 'DataTable per DGV1 Private DT2 As New DataTable 'SelectedIndices per Rows su DGV1 Private selectedRows As New List(Of DataGridViewRow) 'SelectedCells per Cells su DGV2 Private selectedCells As New List(Of DataGridViewCell) Private Sub FormMain_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 'Impostazioni DGV1 - Dimostrazione con Rows With DGV1 .MultiSelect = True .SelectionMode = DataGridViewSelectionMode.FullRowSelect .DefaultCellStyle.SelectionBackColor = Color.Red .DefaultCellStyle.Font = New Font(System.Drawing.FontFamily.GenericSansSerif, 12) .ReadOnly = False .AllowUserToAddRows = False .AllowUserToDeleteRows = True .DataSource = DT1 End With 'Impostazioni DGV2 - Dimostrazione con Celle With DGV2 .MultiSelect = True .SelectionMode = DataGridViewSelectionMode.CellSelect .DefaultCellStyle.SelectionBackColor = Color.Green .DefaultCellStyle.Font = New Font(System.Drawing.FontFamily.GenericSansSerif, 12) .ReadOnly = False .AllowUserToAddRows = False .AllowUserToDeleteRows = True .DataSource = DT2 End With 'DataTable per DGV1 With DT1 'Colonna PK .Columns.Add("ID") .PrimaryKey = New DataColumn() {.Columns("ID")} 'In VB 2010 può essere anche : '.PrimaryKey = {.Columns("ID")} 'Altre Colonne For i As Integer = 1 To 9 .Columns.Add("Colonna_" & i.ToString.PadLeft(2, "0")) Next '... 'Inserimento Rows Dim R As DataRow For i As Integer = 0 To 9 R = .NewRow R(0) = i For j As Integer = 1 To .Columns.Count - 1 R(j) = "Cella_" & j Next .Rows.Add(R) Next End With 'DataTable per DGV2 With DT2 'Colonna PK .Columns.Add("ID") .PrimaryKey = New DataColumn() {.Columns("ID")} 'In VB 2010 può essere anche : '.PrimaryKey = {.Columns("ID")} 'Altre Colonne For i As Integer = 1 To 9 .Columns.Add("Colonna_" & i.ToString.PadLeft(2, "0")) Next '... 'Inserimento Rows Dim R As DataRow For i As Integer = 0 To 9 R = .NewRow R(0) = i For j As Integer = 1 To .Columns.Count - 1 R(j) = "Cella_" & j Next .Rows.Add(R) Next End With End Sub Private Sub CheckCurrentDgv1() If DGV1.CurrentRow Is Nothing Then Exit Sub If selectedRows.Contains(DGV1.CurrentRow) Then selectedRows.Remove(DGV1.CurrentRow) Else selectedRows.Add(DGV1.CurrentRow) End If SelezioneDgv1() End Sub Private Sub SelezioneDgv1() For Each dgvr As DataGridViewRow In DGV1.Rows If selectedRows.Contains(dgvr) Then dgvr.Selected = True Else dgvr.Selected = False End If Next lst_dgv1.Items.Clear() lst_dgv1.Items.AddRange(selectedRows.ToArray) End Sub Private Sub DGV1_CurrentCellChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles DGV1.CurrentCellChanged CheckCurrentDgv1() End Sub Private Sub DGV1_CellBeginEdit(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellCancelEventArgs) Handles DGV1.CellBeginEdit SelezioneDgv1() End Sub Private Sub DGV1_UserDeletingRow(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewRowCancelEventArgs) Handles DGV1.UserDeletingRow If selectedRows.Contains(e.Row) Then selectedRows.Remove(e.Row) SelezioneDgv1() End Sub Private Sub DGV1_DoubleClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles DGV1.DoubleClick CheckCurrentDgv1() End Sub Private Sub CheckCurrentDgv2() If DGV2.CurrentCell Is Nothing Then Exit Sub If selectedCells.Contains(DGV2.CurrentCell) Then selectedCells.Remove(DGV2.CurrentCell) Else selectedCells.Add(DGV2.CurrentCell) End If SelezioneDgv2() End Sub Private Sub SelezioneDgv2() For Each dgvr As DataGridViewRow In DGV2.Rows For Each dgvc As DataGridViewCell In dgvr.Cells If selectedCells.Contains(dgvc) Then dgvc.Selected = True Else dgvc.Selected = False End If Next Next lst_dgv2.Items.Clear() lst_dgv2.Items.AddRange(selectedCells.ToArray) End Sub Private Sub DGV2_CurrentCellChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles DGV2.CurrentCellChanged CheckCurrentDgv2() End Sub Private Sub DGV2_CellBeginEdit(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellCancelEventArgs) Handles DGV2.CellBeginEdit SelezioneDgv2() End Sub Private Sub DGV2_UserDeletingRow(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewRowCancelEventArgs) Handles DGV2.UserDeletingRow For Each dgvc As DataGridViewCell In e.Row.Cells If selectedCells.Contains(dgvc) Then selectedCells.Remove(dgvc) Next SelezioneDgv2() End Sub Private Sub DGV2_DoubleClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles DGV2.DoubleClick CheckCurrentDgv2() End Sub End Class
Per quanto riguarda la parte Dati il codice è già ben commentato.
Con un paio di semplici Metodi scritti ad hoc e 4 Eventi ( comunque molto compatti ), il gioco è fatto.
Come si può notare, la tecnica tiene conto anche dell'eventuale eliminazione di Righe da parte dell'utente.
Inoltre L'Edit di Cella funziona in ogni caso, con Riga o Cella selezionata e non, e come è possibile notare ...
... non reca disturbi sulle pregresse selezioni.
Ovviamente il passo successivo ( che lascio ai lettori ) sarà quello di crearsi una propria Classe che eredita da DataGridView, e che conterrà questi ed altri Metodi ed Eventi, a seconda delle esigenze.
+ Fine Articolo.
2 commenti:
come al solito posso solo dire una cosa Bravo, sei sempre
Preciso e costruttivo, complimenti hai colmato una lacuna
e te ne sono grato, almeno da parte mia
scusa non ho firmato il messaggio
Posta un commento