Procédure pas à pas : implémentation du mode virtuel dans le contrôle DataGridView Windows Forms
Mise à jour : novembre 2007
Lorsque vous souhaitez afficher de très grandes quantités de données sous forme de tableau dans un contrôle DataGridView, vous pouvez affecter à la propriété VirtualMode la valeur true et gérer explicitement l'interaction du contrôle avec son magasin de données. Cela vous permet de régler avec précision la performance du contrôle dans cette situation.
Le contrôle DataGridView fournit plusieurs événements que vous pouvez gérer pour interagir avec un magasin de données personnalisé. Cette procédure pas à pas vous guide à travers le processus d'implémentation de ces gestionnaires d'événements. L'exemple de code dans cette rubrique utilise une source de données très simple au titre d'illustration. Dans un cadre de production, vous chargez en général uniquement les lignes que vous devez afficher dans un cache, et gérez les événements DataGridView pour interagir avec le cache et le mettre à jour. Pour plus d'informations, consultez Implémentation du mode virtuel avec le chargement de données juste-à-temps dans le contrôle DataGridView Windows Forms
Pour copier le code dans cette rubrique sous forme de liste unique, consultez Comment : implémenter le mode virtuel dans le contrôle DataGridView Windows Forms.
Création du formulaire
Pour implémenter le mode virtuel
Créez une classe qui dérive de Form et contient un contrôle DataGridView.
Le code suivant contient une initialisation de base. Il déclare quelques variables qui seront utilisées dans les étapes ultérieures, fournit une méthode Main et fournit une présentation de formulaire simple dans le constructeur de classe.
Imports System Imports System.Windows.Forms Public Class Form1 Inherits Form Private WithEvents dataGridView1 As New DataGridView() ' Declare an ArrayList to serve as the data store. Private customers As New System.Collections.ArrayList() ' Declare a Customer object to store data for a row being edited. Private customerInEdit As Customer ' Declare a variable to store the index of a row being edited. ' A value of -1 indicates that there is no row currently in edit. Private rowInEdit As Integer = -1 ' Declare a variable to indicate the commit scope. ' Set this value to false to use cell-level commit scope. Private rowScopeCommit As Boolean = True <STAThreadAttribute()> _ Public Shared Sub Main() Application.Run(New Form1()) End Sub Public Sub New() ' Initialize the form. Me.dataGridView1.Dock = DockStyle.Fill Me.Controls.Add(Me.dataGridView1) Me.Text = "DataGridView virtual-mode demo (row-level commit scope)" End Sub ... End Class
using System; using System.Windows.Forms; public class Form1 : Form { private DataGridView dataGridView1 = new DataGridView(); // Declare an ArrayList to serve as the data store. private System.Collections.ArrayList customers = new System.Collections.ArrayList(); // Declare a Customer object to store data for a row being edited. private Customer customerInEdit; // Declare a variable to store the index of a row being edited. // A value of -1 indicates that there is no row currently in edit. private int rowInEdit = -1; // Declare a variable to indicate the commit scope. // Set this value to false to use cell-level commit scope. private bool rowScopeCommit = true; [STAThreadAttribute()] public static void Main() { Application.Run(new Form1()); } public Form1() { // Initialize the form. this.dataGridView1.Dock = DockStyle.Fill; this.Controls.Add(this.dataGridView1); this.Load += new EventHandler(Form1_Load); this.Text = "DataGridView virtual-mode demo (row-level commit scope)"; } ... }
Implémentez un gestionnaire pour l'événement Load de votre formulaire qui initialise le contrôle DataGridView et remplit le magasin de données avec des valeurs d'échantillon.
Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) _ Handles Me.Load ' Enable virtual mode. Me.dataGridView1.VirtualMode = True ' Add columns to the DataGridView. Dim companyNameColumn As New DataGridViewTextBoxColumn() With companyNameColumn .HeaderText = "Company Name" .Name = "Company Name" End With Dim contactNameColumn As New DataGridViewTextBoxColumn() With contactNameColumn .HeaderText = "Contact Name" .Name = "Contact Name" End With Me.dataGridView1.Columns.Add(companyNameColumn) Me.dataGridView1.Columns.Add(contactNameColumn) Me.dataGridView1.AutoSizeColumnsMode = _ DataGridViewAutoSizeColumnsMode.AllCells ' Add some sample entries to the data store. Me.customers.Add(New Customer("Bon app'", "Laurence Lebihan")) Me.customers.Add(New Customer("Bottom-Dollar Markets", _ "Elizabeth Lincoln")) Me.customers.Add(New Customer("B's Beverages", "Victoria Ashworth")) ' Set the row count, including the row for new records. Me.dataGridView1.RowCount = 4 End Sub
private void Form1_Load(object sender, EventArgs e) { // Enable virtual mode. this.dataGridView1.VirtualMode = true; // Connect the virtual-mode events to event handlers. this.dataGridView1.CellValueNeeded += new DataGridViewCellValueEventHandler(dataGridView1_CellValueNeeded); this.dataGridView1.CellValuePushed += new DataGridViewCellValueEventHandler(dataGridView1_CellValuePushed); this.dataGridView1.NewRowNeeded += new DataGridViewRowEventHandler(dataGridView1_NewRowNeeded); this.dataGridView1.RowValidated += new DataGridViewCellEventHandler(dataGridView1_RowValidated); this.dataGridView1.RowDirtyStateNeeded += new QuestionEventHandler(dataGridView1_RowDirtyStateNeeded); this.dataGridView1.CancelRowEdit += new QuestionEventHandler(dataGridView1_CancelRowEdit); this.dataGridView1.UserDeletingRow += new DataGridViewRowCancelEventHandler(dataGridView1_UserDeletingRow); // Add columns to the DataGridView. DataGridViewTextBoxColumn companyNameColumn = new DataGridViewTextBoxColumn(); companyNameColumn.HeaderText = "Company Name"; companyNameColumn.Name = "Company Name"; DataGridViewTextBoxColumn contactNameColumn = new DataGridViewTextBoxColumn(); contactNameColumn.HeaderText = "Contact Name"; contactNameColumn.Name = "Contact Name"; this.dataGridView1.Columns.Add(companyNameColumn); this.dataGridView1.Columns.Add(contactNameColumn); this.dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells; // Add some sample entries to the data store. this.customers.Add(new Customer( "Bon app'", "Laurence Lebihan")); this.customers.Add(new Customer( "Bottom-Dollar Markets", "Elizabeth Lincoln")); this.customers.Add(new Customer( "B's Beverages", "Victoria Ashworth")); // Set the row count, including the row for new records. this.dataGridView1.RowCount = 4; }
Implémentez un gestionnaire pour l'événement CellValueNeeded qui récupère la valeur de cellule demandée dans le magasin de données ou l'objet Customer en cours de modification.
Cet événement se produit chaque fois que le contrôle DataGridView doit peindre une cellule.
Private Sub dataGridView1_CellValueNeeded(ByVal sender As Object, _ ByVal e As System.Windows.Forms.DataGridViewCellValueEventArgs) _ Handles dataGridView1.CellValueNeeded ' If this is the row for new records, no values are needed. If e.RowIndex = Me.dataGridView1.RowCount - 1 Then Return End If Dim customerTmp As Customer = Nothing ' Store a reference to the Customer object for the row being painted. If e.RowIndex = rowInEdit Then customerTmp = Me.customerInEdit Else customerTmp = CType(Me.customers(e.RowIndex), Customer) End If ' Set the cell value to paint using the Customer object retrieved. Select Case Me.dataGridView1.Columns(e.ColumnIndex).Name Case "Company Name" e.Value = customerTmp.CompanyName Case "Contact Name" e.Value = customerTmp.ContactName End Select End Sub
private void dataGridView1_CellValueNeeded(object sender, System.Windows.Forms.DataGridViewCellValueEventArgs e) { // If this is the row for new records, no values are needed. if (e.RowIndex == this.dataGridView1.RowCount - 1) return; Customer customerTmp = null; // Store a reference to the Customer object for the row being painted. if (e.RowIndex == rowInEdit) { customerTmp = this.customerInEdit; } else { customerTmp = (Customer)this.customers[e.RowIndex]; } // Set the cell value to paint using the Customer object retrieved. switch (this.dataGridView1.Columns[e.ColumnIndex].Name) { case "Company Name": e.Value = customerTmp.CompanyName; break; case "Contact Name": e.Value = customerTmp.ContactName; break; } }
Implémentez un gestionnaire pour l'événement CellValuePushed qui stocke une valeur de cellule modifiée dans l'objet Customer qui représente la ligne modifiée. Cet événement se produit chaque fois que l'utilisateur valide un changement de valeur de la cellule.
Private Sub dataGridView1_CellValuePushed(ByVal sender As Object, _ ByVal e As System.Windows.Forms.DataGridViewCellValueEventArgs) _ Handles dataGridView1.CellValuePushed Dim customerTmp As Customer = Nothing ' Store a reference to the Customer object for the row being edited. If e.RowIndex < Me.customers.Count Then ' If the user is editing a new row, create a new Customer object. If Me.customerInEdit Is Nothing Then Me.customerInEdit = New Customer( _ CType(Me.customers(e.RowIndex), Customer).CompanyName, _ CType(Me.customers(e.RowIndex), Customer).ContactName) End If customerTmp = Me.customerInEdit Me.rowInEdit = e.RowIndex Else customerTmp = Me.customerInEdit End If ' Set the appropriate Customer property to the cell value entered. Dim newValue As String = TryCast(e.Value, String) Select Case Me.dataGridView1.Columns(e.ColumnIndex).Name Case "Company Name" customerTmp.CompanyName = newValue Case "Contact Name" customerTmp.ContactName = newValue End Select End Sub
private void dataGridView1_CellValuePushed(object sender, System.Windows.Forms.DataGridViewCellValueEventArgs e) { Customer customerTmp = null; // Store a reference to the Customer object for the row being edited. if (e.RowIndex < this.customers.Count) { // If the user is editing a new row, create a new Customer object. if (this.customerInEdit == null) { this.customerInEdit = new Customer( ((Customer)this.customers[e.RowIndex]).CompanyName, ((Customer)this.customers[e.RowIndex]).ContactName); } customerTmp = this.customerInEdit; this.rowInEdit = e.RowIndex; } else { customerTmp = this.customerInEdit; } // Set the appropriate Customer property to the cell value entered. String newValue = e.Value as String; switch (this.dataGridView1.Columns[e.ColumnIndex].Name) { case "Company Name": customerTmp.CompanyName = newValue; break; case "Contact Name": customerTmp.ContactName = newValue; break; } }
Implémentez un gestionnaire pour l'événement NewRowNeeded qui crée un nouvel objet Customer représentant une ligne nouvellement créée.
Cet événement se produit chaque fois que l'utilisateur entre dans la ligne pour de nouveaux enregistrements.
Private Sub dataGridView1_NewRowNeeded(ByVal sender As Object, _ ByVal e As System.Windows.Forms.DataGridViewRowEventArgs) _ Handles dataGridView1.NewRowNeeded ' Create a new Customer object when the user edits ' the row for new records. Me.customerInEdit = New Customer() Me.rowInEdit = Me.dataGridView1.Rows.Count - 1 End Sub
private void dataGridView1_NewRowNeeded(object sender, System.Windows.Forms.DataGridViewRowEventArgs e) { // Create a new Customer object when the user edits // the row for new records. this.customerInEdit = new Customer(); this.rowInEdit = this.dataGridView1.Rows.Count - 1; }
Implémentez un gestionnaire pour l'événement RowValidated qui enregistre les lignes nouvelles ou modifiées dans le magasin de données.
Cet événement se produit chaque fois que l'utilisateur change la ligne actuelle.
Private Sub dataGridView1_RowValidated(ByVal sender As Object, _ ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) _ Handles dataGridView1.RowValidated ' Save row changes if any were made and release the edited ' Customer object if there is one. If e.RowIndex >= Me.customers.Count AndAlso _ e.RowIndex <> Me.dataGridView1.Rows.Count - 1 Then ' Add the new Customer object to the data store. Me.customers.Add(Me.customerInEdit) Me.customerInEdit = Nothing Me.rowInEdit = -1 ElseIf (Me.customerInEdit IsNot Nothing) AndAlso _ e.RowIndex < Me.customers.Count Then ' Save the modified Customer object in the data store. Me.customers(e.RowIndex) = Me.customerInEdit Me.customerInEdit = Nothing Me.rowInEdit = -1 ElseIf Me.dataGridView1.ContainsFocus Then Me.customerInEdit = Nothing Me.rowInEdit = -1 End If End Sub
private void dataGridView1_RowValidated(object sender, System.Windows.Forms.DataGridViewCellEventArgs e) { // Save row changes if any were made and release the edited // Customer object if there is one. if (e.RowIndex >= this.customers.Count && e.RowIndex != this.dataGridView1.Rows.Count - 1) { // Add the new Customer object to the data store. this.customers.Add(this.customerInEdit); this.customerInEdit = null; this.rowInEdit = -1; } else if (this.customerInEdit != null && e.RowIndex < this.customers.Count) { // Save the modified Customer object in the data store. this.customers[e.RowIndex] = this.customerInEdit; this.customerInEdit = null; this.rowInEdit = -1; } else if (this.dataGridView1.ContainsFocus) { this.customerInEdit = null; this.rowInEdit = -1; } }
Implémentez un gestionnaire pour l'événement RowDirtyStateNeeded qui indique si l'événement CancelRowEdit se produit lorsque l'utilisateur signale une inversion de ligne en appuyant deux fois sur ÉCHAP en mode édition, ou une fois dans un autre mode.
Par défaut, CancelRowEdit se produit en cas d'inversion de ligne lorsque chaque cellule de la ligne actuelle a été modifiée, sauf si la propriété QuestionEventArgs.Response a la valeur true dans le gestionnaire d'événements RowDirtyStateNeeded. Cet événement est utile lorsque la portée de validation est déterminée au moment de l'exécution.
Private Sub dataGridView1_RowDirtyStateNeeded(ByVal sender As Object, _ ByVal e As System.Windows.Forms.QuestionEventArgs) _ Handles dataGridView1.RowDirtyStateNeeded If Not rowScopeCommit Then ' In cell-level commit scope, indicate whether the value ' of the current cell has been modified. e.Response = Me.dataGridView1.IsCurrentCellDirty End If End Sub
private void dataGridView1_RowDirtyStateNeeded(object sender, System.Windows.Forms.QuestionEventArgs e) { if (!rowScopeCommit) { // In cell-level commit scope, indicate whether the value // of the current cell has been modified. e.Response = this.dataGridView1.IsCurrentCellDirty; } }
Implémentez un gestionnaire pour l'événement CancelRowEdit qui ignore les valeurs de l'objet Customer représentant la ligne actuelle.
Cet événement se produit lorsque l'utilisateur signale l'inversion de ligne en appuyant deux fois sur ÉCHAP en mode édition, ou une fois dans un autre mode. Cet événement ne se produit pas si aucune cellule de la ligne actuelle n'a été modifiée ou si la valeur false a été affectée à la propriété QuestionEventArgs.Response dans un gestionnaire d'événements RowDirtyStateNeeded.
Private Sub dataGridView1_CancelRowEdit(ByVal sender As Object, _ ByVal e As System.Windows.Forms.QuestionEventArgs) _ Handles dataGridView1.CancelRowEdit If Me.rowInEdit = Me.dataGridView1.Rows.Count - 2 AndAlso _ Me.rowInEdit = Me.customers.Count Then ' If the user has canceled the edit of a newly created row, ' replace the corresponding Customer object with a new, empty one. Me.customerInEdit = New Customer() Else ' If the user has canceled the edit of an existing row, ' release the corresponding Customer object. Me.customerInEdit = Nothing Me.rowInEdit = -1 End If End Sub
private void dataGridView1_CancelRowEdit(object sender, System.Windows.Forms.QuestionEventArgs e) { if (this.rowInEdit == this.dataGridView1.Rows.Count - 2 && this.rowInEdit == this.customers.Count) { // If the user has canceled the edit of a newly created row, // replace the corresponding Customer object with a new, empty one. this.customerInEdit = new Customer(); } else { // If the user has canceled the edit of an existing row, // release the corresponding Customer object. this.customerInEdit = null; this.rowInEdit = -1; } }
Implémentez un gestionnaire pour l'événement UserDeletingRow qui supprime un objet Customer existant dans le magasin de données ou ignore un objet Customer non enregistré qui représente une ligne venant d'être créée.
Cet événement se produit chaque fois que l'utilisateur supprime une ligne en cliquant sur un en-tête de ligne et en appuyant sur la touche SUPPR.
Private Sub dataGridView1_UserDeletingRow(ByVal sender As Object, _ ByVal e As System.Windows.Forms.DataGridViewRowCancelEventArgs) _ Handles dataGridView1.UserDeletingRow If e.Row.Index < Me.customers.Count Then ' If the user has deleted an existing row, remove the ' corresponding Customer object from the data store. Me.customers.RemoveAt(e.Row.Index) End If If e.Row.Index = Me.rowInEdit Then ' If the user has deleted a newly created row, release ' the corresponding Customer object. Me.rowInEdit = -1 Me.customerInEdit = Nothing End If End Sub
private void dataGridView1_UserDeletingRow(object sender, System.Windows.Forms.DataGridViewRowCancelEventArgs e) { if (e.Row.Index < this.customers.Count) { // If the user has deleted an existing row, remove the // corresponding Customer object from the data store. this.customers.RemoveAt(e.Row.Index); } if (e.Row.Index == this.rowInEdit) { // If the user has deleted a newly created row, release // the corresponding Customer object. this.rowInEdit = -1; this.customerInEdit = null; } }
Implémentez une classe Customers simple pour représenter les éléments de données utilisés par cet exemple de code.
Public Class Customer Private companyNameValue As String Private contactNameValue As String Public Sub New() ' Leave fields empty. End Sub Public Sub New(ByVal companyName As String, ByVal contactName As String) companyNameValue = companyName contactNameValue = contactName End Sub Public Property CompanyName() As String Get Return companyNameValue End Get Set(ByVal value As String) companyNameValue = value End Set End Property Public Property ContactName() As String Get Return contactNameValue End Get Set(ByVal value As String) contactNameValue = value End Set End Property End Class
public class Customer { private String companyNameValue; private String contactNameValue; public Customer() { // Leave fields empty. } public Customer(String companyName, String contactName) { companyNameValue = companyName; contactNameValue = contactName; } public String CompanyName { get { return companyNameValue; } set { companyNameValue = value; } } public String ContactName { get { return contactNameValue; } set { contactNameValue = value; } } }
Test de l'application
Vous pouvez à présent tester le formulaire afin de vous assurer qu'il se comporte comme prévu.
Pour tester le formulaire
Compilez et exécutez l'application.
Vous observerez un contrôle DataGridView rempli de trois enregistrements de client. Vous pouvez modifier les valeurs de plusieurs cellules dans une ligne et appuyer deux fois sur ÉCHAP en mode édition, ou une fois dans un autre mode, pour redonner à toute la ligne ses valeurs d'origine. Lorsque vous modifiez, ajoutez ou supprimez des lignes dans le contrôle, les objets Customer dans le magasin de données sont également modifiés, ajoutés ou supprimés.
Étapes suivantes
Cette application vous donne des notions de base sur les événements que vous devez gérer pour implémenter le mode virtuel dans le contrôle DataGridView. Vous pouvez améliorer cette application de base de plusieurs manières :
Implémentez un magasin de données qui mette en cache des valeurs d'une base de données externe. Le cache doit récupérer ou ignorer au besoin les valeurs de sorte qu'il ne contienne que les éléments devant être affichés tout en consommant une petite quantité de mémoire sur l'ordinateur client.
Réglez avec précision la performance du magasin de données selon vos besoins. Par exemple, vous pouvez chercher à compenser la lenteur des connexions réseau plutôt que les limitations de mémoire de l'ordinateur client en utilisant une taille de cache plus grande et en réduisant le nombre de requêtes de base de données.
Pour plus d'informations sur la mise en cache de valeurs à partir d'une base de données externe, consultez Comment : implémenter le mode virtuel avec le chargement de données juste-à-temps dans le contrôle DataGridView Windows Forms.
Voir aussi
Tâches
Comment : implémenter le mode virtuel dans le contrôle DataGridView Windows Forms
Concepts
Méthodes conseillées pour la mise à l'échelle du contrôle DataGridView Windows Forms
Référence
Autres ressources
Réglage des performances dans le contrôle DataGridView Windows Forms