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 ClassPer 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.



14:49
MarcoGG



Posted in:
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