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 :
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.
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 :
using System; using System.Collections.Generic; using System.Data; using System.Drawing; using System.Windows.Forms; namespace DGVMultiSelect { public partial class FormMain : Form { public FormMain() { InitializeComponent(); } //DataTable per DGV1 private DataTable DT1 = new DataTable(); //DataTable per DGV1 private DataTable DT2 = new DataTable(); //SelectedIndices per Rows su DGV1 private List<DataGridViewRow> selectedRows = new List<DataGridViewRow>(); //SelectedCells per Cells su DGV2 private List<DataGridViewCell> selectedCells = new List<DataGridViewCell>(); private void FormMain_Load(object sender, EventArgs e) { //Impostazioni DGV1 - Dimostrazione con Rows DGV1.MultiSelect = true; DGV1.SelectionMode = DataGridViewSelectionMode.FullRowSelect; DGV1.DefaultCellStyle.SelectionBackColor = Color.Red; DGV1.DefaultCellStyle.Font = new Font(System.Drawing.FontFamily.GenericSansSerif, 12); DGV1.ReadOnly = false; DGV1.AllowUserToAddRows = false; DGV1.AllowUserToDeleteRows = true; DGV1.DataSource = DT1; //Impostazioni DGV2 - Dimostrazione con Celle DGV2.MultiSelect = true; DGV2.SelectionMode = DataGridViewSelectionMode.CellSelect; DGV2.DefaultCellStyle.SelectionBackColor = Color.Green; DGV2.DefaultCellStyle.Font = new Font(System.Drawing.FontFamily.GenericSansSerif, 12); DGV2.ReadOnly = false; DGV2.AllowUserToAddRows = false; DGV2.AllowUserToDeleteRows = true; DGV2.DataSource = DT2; //DataTable per DGV1 //Colonna PK DT1.Columns.Add("ID"); DT1.PrimaryKey = new DataColumn[] {DT1.Columns["ID"]}; //Altre Colonne for (int i = 1; i <= 9; i++) { DT1.Columns.Add("Colonna_" + i.ToString().PadLeft(2, '0')); } //... //Inserimento Rows DataRow R = null; for (int i = 0; i <= 9; i++) { R = DT1.NewRow(); R[0] = i; for (int j = 1; j < DT1.Columns.Count; j++) { R[j] = "Cella_" + j; } DT1.Rows.Add(R); } //DataTable per DGV2 //Colonna PK DT2.Columns.Add("ID"); DT2.PrimaryKey = new DataColumn[] {DT2.Columns["ID"]}; //Altre Colonne for (int i = 1; i <= 9; i++) { DT2.Columns.Add("Colonna_" + i.ToString().PadLeft(2, '0')); } //... //Inserimento Rows for (int i = 0; i <= 9; i++) { R = DT2.NewRow(); R[0] = i; for (int j = 1; j < DT2.Columns.Count; j++) { R[j] = "Cella_" + j; } DT2.Rows.Add(R); } } private void CheckCurrentDgv1() { if (DGV1.CurrentRow == null) { return; } if (selectedRows.Contains(DGV1.CurrentRow)) { selectedRows.Remove(DGV1.CurrentRow); } else { selectedRows.Add(DGV1.CurrentRow); } SelezioneDgv1(); } private void SelezioneDgv1() { foreach (DataGridViewRow dgvr in DGV1.Rows) { if (selectedRows.Contains(dgvr)) { dgvr.Selected = true; } else { dgvr.Selected = false; } } lst_dgv1.Items.Clear(); lst_dgv1.Items.AddRange(selectedRows.ToArray()); } private void DGV1_CurrentCellChanged(object sender, EventArgs e) { CheckCurrentDgv1(); } private void DGV1_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e) { SelezioneDgv1(); } private void DGV1_UserDeletingRow(object sender, DataGridViewRowCancelEventArgs e) { if (selectedRows.Contains(e.Row)) { selectedRows.Remove(e.Row); } SelezioneDgv1(); } private void DGV1_DoubleClick(object sender, EventArgs e) { CheckCurrentDgv1(); } private void CheckCurrentDgv2() { if (DGV2.CurrentCell == null) { return; } if (selectedCells.Contains(DGV2.CurrentCell)) { selectedCells.Remove(DGV2.CurrentCell); } else { selectedCells.Add(DGV2.CurrentCell); } SelezioneDgv2(); } private void SelezioneDgv2() { foreach (DataGridViewRow dgvr in DGV2.Rows) { foreach (DataGridViewCell dgvc in dgvr.Cells) { if (selectedCells.Contains(dgvc)) { dgvc.Selected = true; } else { dgvc.Selected = false; } } } lst_dgv2.Items.Clear(); lst_dgv2.Items.AddRange(selectedCells.ToArray()); } private void DGV2_CurrentCellChanged(object sender, EventArgs e) { CheckCurrentDgv2(); } private void DGV2_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e) { SelezioneDgv2(); } private void DGV2_UserDeletingRow(object sender, DataGridViewRowCancelEventArgs e) { foreach (DataGridViewCell dgvc in e.Row.Cells) { if (selectedCells.Contains(dgvc)) { selectedCells.Remove(dgvc); } } SelezioneDgv2(); } private void DGV2_DoubleClick(object sender, EventArgs e) { CheckCurrentDgv2(); } } }
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.