How to: Implement Virtual Mode in the Windows Forms DataGridView Control

The following code example demonstrates how to manage large sets of data using a DataGridView control with its VirtualMode property set to true.

For a complete explanation of this code example, see Walkthrough: Implementing Virtual Mode in the Windows Forms DataGridView Control.

Example

#using <System.Drawing.dll>
#using <System.dll>
#using <System.Windows.Forms.dll>

using namespace System;
using namespace System::Windows::Forms;

public ref class Customer
{
private:
   String^ companyNameValue;
   String^ contactNameValue;

public:
   Customer()
   {
      
      // Leave fields empty.
   }

   Customer( String^ companyName, String^ contactName )
   {
      companyNameValue = companyName;
      contactNameValue = contactName;
   }


   property String^ CompanyName 
   {
      String^ get()
      {
         return companyNameValue;
      }

      void set( String^ value )
      {
         companyNameValue = value;
      }

   }

   property String^ ContactName 
   {
      String^ get()
      {
         return contactNameValue;
      }

      void set( String^ value )
      {
         contactNameValue = value;
      }

   }

};

public ref class Form1: public Form
{
private:
   DataGridView^ dataGridView1;

   // Declare an ArrayList to serve as the data store. 
   System::Collections::ArrayList^ customers;

   // Declare a Customer object to store data for a row being edited.
   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. 
   int rowInEdit;

   // Declare a variable to indicate the commit scope. 
   // Set this value to false to use cell-level commit scope. 
   bool rowScopeCommit;

public:
   static void Main()
   {
      Application::Run( gcnew Form1 );
   }

   Form1()
   {
      dataGridView1 = gcnew DataGridView;
      customers = gcnew System::Collections::ArrayList;
      rowInEdit = -1;
      rowScopeCommit = true;
      
      // Initialize the form.
      this->dataGridView1->Dock = DockStyle::Fill;
      this->Controls->Add( this->dataGridView1 );
      this->Load += gcnew EventHandler( this, &Form1::Form1_Load );
   }

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 += gcnew
          DataGridViewCellValueEventHandler( this, &Form1::dataGridView1_CellValueNeeded );
      this->dataGridView1->CellValuePushed += gcnew
          DataGridViewCellValueEventHandler( this, &Form1::dataGridView1_CellValuePushed );
      this->dataGridView1->NewRowNeeded += gcnew
          DataGridViewRowEventHandler( this, &Form1::dataGridView1_NewRowNeeded );
      this->dataGridView1->RowValidated += gcnew
          DataGridViewCellEventHandler( this, &Form1::dataGridView1_RowValidated );
      this->dataGridView1->RowDirtyStateNeeded += gcnew
          QuestionEventHandler( this, &Form1::dataGridView1_RowDirtyStateNeeded );
      this->dataGridView1->CancelRowEdit += gcnew
          QuestionEventHandler( this, &Form1::dataGridView1_CancelRowEdit );
      this->dataGridView1->UserDeletingRow += gcnew
          DataGridViewRowCancelEventHandler( this, &Form1::dataGridView1_UserDeletingRow );
      
      // Add columns to the DataGridView.
      DataGridViewTextBoxColumn^ companyNameColumn = gcnew DataGridViewTextBoxColumn;
      companyNameColumn->HeaderText = L"Company Name";
      companyNameColumn->Name = L"Company Name";
      DataGridViewTextBoxColumn^ contactNameColumn = gcnew DataGridViewTextBoxColumn;
      contactNameColumn->HeaderText = L"Contact Name";
      contactNameColumn->Name = L"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( gcnew Customer( L"Bon app'",L"Laurence Lebihan" ) );
      this->customers->Add( gcnew Customer( L"Bottom-Dollar Markets",L"Elizabeth Lincoln" ) );
      this->customers->Add( gcnew Customer( L"B's Beverages",L"Victoria Ashworth" ) );
      
      // Set the row count, including the row for new records.
      this->dataGridView1->RowCount = 4;
   }

   void dataGridView1_CellValueNeeded( Object^ /*sender*/,
       System::Windows::Forms::DataGridViewCellValueEventArgs^ e )
   {
      Customer^ customerTmp = nullptr;
      
      // Store a reference to the Customer object for the row being painted.
      if ( e->RowIndex == rowInEdit )
      {
         customerTmp = this->customerInEdit;
      }
      else
      {
         customerTmp = dynamic_cast<Customer^>(this->customers[ e->RowIndex ]);
      }
      
      // Set the cell value to paint using the Customer object retrieved.
      int switchcase = 0;
      if ( (this->dataGridView1->Columns[ e->ColumnIndex ]->Name)->Equals( L"Company Name" ) )
            switchcase = 1;
      else
      if ( (this->dataGridView1->Columns[ e->ColumnIndex ]->Name)->Equals( L"Contact Name" ) )
            switchcase = 2;


      switch ( switchcase )
      {
         case 1:
            e->Value = customerTmp->CompanyName;
            break;

         case 2:
            e->Value = customerTmp->ContactName;
            break;
      }
   }


   void dataGridView1_CellValuePushed( Object^ /*sender*/,
       System::Windows::Forms::DataGridViewCellValueEventArgs^ e )
   {
      Customer^ customerTmp = nullptr;
      
      // 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 == nullptr )
         {
            this->customerInEdit = gcnew Customer(
                (dynamic_cast<Customer^>(this->customers[ e->RowIndex ]))->CompanyName,
                (dynamic_cast<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.
      int switchcase = 0;
      if ( (this->dataGridView1->Columns[ e->ColumnIndex ]->Name)->Equals( L"Company Name" ) )
            switchcase = 1;
      else
      if ( (this->dataGridView1->Columns[ e->ColumnIndex ]->Name)->Equals( L"Contact Name" ) )
            switchcase = 2;


      switch ( switchcase )
      {
         case 1:
            customerTmp->CompanyName = dynamic_cast<String^>(e->Value);
            break;

         case 2:
            customerTmp->ContactName = dynamic_cast<String^>(e->Value);
            break;
      }
   }


   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 = gcnew Customer;
      this->rowInEdit = this->dataGridView1->Rows->Count - 1;
   }


   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 = nullptr;
         this->rowInEdit = -1;
      }
      else
      if ( this->customerInEdit != nullptr && e->RowIndex < this->customers->Count )
      {
         
         // Save the modified Customer object in the data store.
         this->customers[ e->RowIndex ] = this->customerInEdit;
         this->customerInEdit = nullptr;
         this->rowInEdit = -1;
      }
      else
      if ( this->dataGridView1->ContainsFocus )
      {
         this->customerInEdit = nullptr;
         this->rowInEdit = -1;
      }
   }


   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;
      }
   }


   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 = gcnew Customer;
      }
      else
      {
         
         // If the user has canceled the edit of an existing row, 
         // release the corresponding Customer object.
         this->customerInEdit = nullptr;
         this->rowInEdit = -1;
      }
   }


   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 = nullptr;
      }
   }
};

int main()
{
   Form1::Main();
}


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)";
    }

    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;
    }

    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;
        }
    }

    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;
        }
    }

    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;
    }

    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;
        }
    }

    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;
        }
    }

    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;
        }
    }

    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;
        }
    }
}

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;
        }
    }
}
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

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

End Class

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

Compiling the Code

This example requires:

  • References to the System and System.Windows.Forms assemblies.

For information about building this example from the command line for Visual Basic or Visual C#, see Building from the Command Line or Command-line Building With csc.exe. You can also build this example in Visual Studio by pasting the code into a new project. Also see How to: Compile and Run a Complete Windows Forms Code Example Using Visual Studio.

See Also

DataGridView
VirtualMode
CellValueNeeded
CellValuePushed
NewRowNeeded
RowValidated
RowDirtyStateNeeded
CancelRowEdit
UserDeletingRow
Walkthrough: Implementing Virtual Mode in the Windows Forms DataGridView Control
Performance Tuning in the Windows Forms DataGridView Control
Virtual Mode in the Windows Forms DataGridView Control