Condividi tramite


Procedura dettagliata: implementazione della modalità virtuale nel controllo DataGridView Windows Form

Aggiornamento: novembre 2007

Quando si desidera visualizzare quantità molto elevate di dati in formato tabulare in un controllo DataGridView, è possibile impostare la proprietà VirtualMode su true e gestire in modo esplicito l'interazione del controllo con il relativo archivio dati. In questo modo è possibile regolare le prestazioni del controllo in una situazione di questo tipo.

Il controllo DataGridView fornisce numerosi eventi che è possibile gestire per consentire l'interazione con un archivio dati personalizzato. Questa procedura dettagliata rappresenta una guida nel processo di implementazione di questi gestori eventi. Nell'esempio di codice riportato in questo argomento viene utilizzata un'origine dati semplice a scopo illustrativo. Nell'impostazione di un ambiente la produzione, in genere vengono caricate solo le righe che è necessario visualizzare in una cache e vengono gestiti gli eventi DataGridView per l'interazione con la cache e il relativo aggiornamento. Per ulteriori informazioni, vedere Implementazione del modo virtuale con caricamento dati JIT nel controllo DataGridView di Windows Form

Per copiare il codice nell'argomento corrente come un elenco singolo, vedere Procedura: implementare il modo virtuale nel controllo DataGridView di Windows Form.

Creazione del form

Per implementare la modalità virtuale

  1. Creare una classe derivante dalla classe Form e che contenga un controllo DataGridView.

    Nel codice riportato di seguito viene fornita l'inizializzazione di base. Vengono dichiarate alcune variabili da utilizzare nei passaggi successivi, viene fornito un metodo Main e viene fornito un layout di form semplice nel costruttore della 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)";
        }
    
    
    ...
    
    
    }
    
  2. Implementare un gestore per l'evento Load del form per inizializzare il controllo DataGridView e inserire valori di esempio nell'archivio dati.

    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;
    }
    
  3. Implementare un gestore per l'evento CellValueNeeded per recuperare il valore di cella necessario dall'archivio dati o dall'oggetto Customer attualmente in fase di modifica.

    Questo evento viene generato ogni volta che il controllo DataGridView deve disegnare una cella.

    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;
        }
    }
    
  4. Implementare un gestore per l'evento CellValuePushed per memorizzare un valore di cella modificato nell'oggetto Customer che rappresenta la riga modificata. Questo evento viene generato ogni volta che l'utente esegue il commit di una modifica del valore di una cella.

    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;
        }
    }
    
  5. Implementare un gestore per l'evento NewRowNeeded per creare un nuovo oggetto Customer che rappresenta una riga appena creata.

    Questo evento viene generato quando l'utente inserisce una riga per immettere nuovi record.

    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;
    }
    
  6. Implementare un gestore per l'evento RowValidated per salvare le righe nuove e modificate nell'archivio dati.

    Questo evento si verifica ogni volta che l'utente modifica la riga corrente.

    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;
        }
    }
    
  7. Implementare un gestore per l'evento RowDirtyStateNeeded per indicare se l'evento CancelRowEdit verrà generato quando l'utente segnala l'annullamento della riga premendo due volte il tasto ESC in modalità di modifica o una sola volta al di fuori di tale modalità.

    Per impostazione predefinita, l'evento CancelRowEdit viene generato al momento dell'annullamento della riga quando le celle presenti nella riga corrente sono state modificate, a meno che la proprietà QuestionEventArgs.Response non sia impostata su true nel gestore eventi RowDirtyStateNeeded. Questo evento è utile nel caso in cui l'ambito dell'operazione di commit sia determinata in fase di esecuzione.

    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;
        }
    }
    
  8. Implementare un gestore per l'evento CancelRowEdit per eliminare i valori dell'oggetto Customer che rappresenta la riga corrente.

    Questo evento viene generato quando l'utente segnala l'annullamento della riga premendo due volte il tasto ESC in modalità di modifica o una sola volta al di fuori di tale modalità. Questo evento non viene generato se non sono state modificate celle all'interno della riga corrente oppure se il valore della proprietà QuestionEventArgs.Response è impostato su false in un gestore eventi 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;
        }
    }
    
  9. Implementare un gestore per l'evento UserDeletingRow per eliminare un oggetto Customer già presente dall'archivio dati o eliminare un oggetto Customer non salvato che rappresenta una riga appena creata.

    Questo evento viene generato ogni volta che l'utente elimina una riga selezionando l'intestazione di una riga e premendo il tasto CANC.

    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;
        }
    }
    
  10. Implementare una classe Customers semplice che rappresenti gli elementi di dati utilizzati in questo esempio di codice.

    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 dell'applicazione

È ora possibile verificare il form per assicurarsi che funzioni correttamente.

Per eseguire il test del form

  • Compilare l'applicazione ed eseguirla.

    Verrà visualizzato un controllo DataGridView in cui sono presenti tre record relativi al cliente. È possibile modificare i valori di più celle in una riga e premere ESC due volte in modalità di modifica e una volta al di fuori di tale modalità per ripristinare i valori originali dell'intera riga. Quando si modificano, aggiungono o eliminano righe all'interno del controllo, anche gli oggetti Customer all'interno dell'archivio dati vengono modificati, aggiunti o eliminati.

Passaggi successivi

Questa applicazione consente di comprendere i concetti di base degli eventi che è necessario gestire per implementare la modalità virtuale nel controllo DataGridView. Questa applicazione di base può essere resa più complessa in diversi modi:

  • Implementando un archivio dati per la memorizzazione nella cache dei valori di un database esterno. I valori memorizzati nella cache potranno essere recuperati ed eliminati secondo necessità, in modo che la cache contenga solo gli elementi necessari per la visualizzazione, utilizzando quindi una minore quantità di memoria sul computer client.

  • Regolando le prestazioni dell'archivio dati in base alle esigenze. Ad esempio, è possibile rimediare alla lentezza delle connessioni in rete invece alle limitazioni della memoria del computer client utilizzando dimensioni della memoria cache maggiori e riducendo il numero delle query sul database.

Per ulteriori informazioni sulla memorizzazione nella cache dei valori di un database esterno, vedere Procedura: implementare la modalità virtuale con caricamento dati JIT nel controllo DataGridView di Windows Form.

Vedere anche

Attività

Procedura: implementare il modo virtuale nel controllo DataGridView di Windows Form

Concetti

Procedure consigliate per ridimensionare il controllo DataGridView Windows Form

Implementazione del modo virtuale con caricamento dati JIT nel controllo DataGridView di Windows Form

Riferimenti

DataGridView

VirtualMode

CellValueNeeded

CellValuePushed

NewRowNeeded

RowValidated

RowDirtyStateNeeded

CancelRowEdit

UserDeletingRow

Altre risorse

Ottimizzazione delle prestazioni nel controllo DataGridView Windows Form