共用方式為


逐步解說:在 Windows Form DataGridView 控制項中實作虛擬模式

當您要在 DataGridView 控制項中顯示相當大量的表格式資料時,您可以將 VirtualMode 屬性設定為 true,並明確管理控制項與其資料存放區的互動。 這讓您可以在這種情況下微調控制項的效能。

DataGridView 控制項提供幾個事件,您可以處理這些事件以與自訂的資料存放區互動。 此逐步解說會引導您完成實作這些事件處理常式的過程。 本節中的程式碼範例會使用一個非常簡單的資料來源以進行說明。 在實際執行設定中,您通常只會將需要顯示的資料列載入到快取區 (Cache) 中,並處理 DataGridView 事件以與快取區互動和更新快取區。 如需詳細資訊,請參閱在 Windows Form DataGridView 控制項中以 Just-In-Time 資料載入方式實作虛擬模式

若要將此主題中的程式碼複製為一份清單,請參閱 HOW TO:在 Windows Form DataGridView 控制項中實作虛擬模式

建立表單

若要實作虛擬模式

  1. 建立衍生自 Form 並包含 DataGridView 控制項的類別。

    下列程式碼包含一些基本的初始設定。 它會宣告一些在稍後步驟中會用到的變數、提供 Main 方法,並在類別建構函式中提供簡單的表單配置。

    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)";
        }
    
    
    ...
    
    
    }
    
    #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:
    
    
    ...
    
    
    };
    
    int main()
    {
       Form1::Main();
    }
    
  2. 為表單的 Load 事件實作處理常式,此事件會初始化 DataGridView 控制項,並將範例值填入資料存放區。

    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;
    }
    
       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;
       }
    
  3. 實作 CellValueNeeded 事件的處理常式,此事件會從資料存放區或目前正在編輯的 Customer 物件,擷取要求的儲存格值。

    每當 DataGridView 控制項需要繪製儲存格時,就會發生這個事件。

    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;
        }
    }
    
       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;
          }
       }
    
    
    
  4. 實作 CellValuePushed 事件的處理常式,此事件會在 Customer (代表已編輯的資料列) 物件中儲存已編輯的儲存格值。 每當使用者認可儲存格值的變更時,就會發生這個事件。

    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;
        }
    }
    
       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;
          }
       }
    
    
    
  5. 實作 NewRowNeeded 事件的處理常式,此事件會建立新的 Customer 物件 (代表新建立的資料列)。

    每當使用者輸入新資料錄的資料列時,就會發生這個事件。

    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;
    }
    
       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;
       }
    
    
    
  6. 實作 RowValidated 事件的處理常式,此事件會將新的或已修改的資料列儲存到資料存放區。

    每當使用者變更目前的資料列時,就會發生這個事件。

    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;
        }
    }
    
       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;
          }
       }
    
    
    
  7. 實作 RowDirtyStateNeeded 事件的處理常式,此事件會指示當使用者在編輯模式中按兩次 ESC 鍵,或是在編輯模式之外按一次 ESC 鍵時,發出資料列還原信號,是否會發生 CancelRowEdit 事件。

    依據預設,當目前資料列中的任何儲存格被修改而且還原時,CancelRowEdit 就會發生,除非在 RowDirtyStateNeeded 事件處理常式中,QuestionEventArgs.Response 屬性是設定為 true。 當認可範圍是在執行階段決定時,這個事件相當有用。

    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;
        }
    }
    
       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. 實作 CancelRowEdit 事件的處理常式,此事件會捨棄 Customer 物件 (代表目前的資料列) 的值。

    當使用者在編輯模式中按兩次 ESC 鍵發出資料列還原信號,或是在編輯模式之外按一次 ESC 時,就會發生這個事件。 如果目前的資料列中沒有儲存格被修改,或是在 RowDirtyStateNeeded 事件處理常式中,QuestionEventArgs.Response 屬性的值已設定為 false,就不會發生這個事件。

    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;
        }
    }
    
       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;
          }
       }
    
    
    
  9. 實作 UserDeletingRow 事件的處理常式,此事件會從資料存放區刪除現有的 Customer 物件或捨棄未儲存的 Customer 物件 (代表新建立的資料列)。

    每當使用者按一下資料列行首並按 DELETE 鍵時,就會發生這個事件。

    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;
        }
    }
    
    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;
       }
    }
    
  10. 實作簡單的 Customers 類別,以代表這個程式碼範例所使用的資料項目。

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

測試應用程式

您現在可以測試表單以確定它的行為表現如預期般。

若要測試表單

  • 編譯及執行應用程式。

    您將看到一個填入三筆客戶資料錄的 DataGridView 控制項。 您可以在資料列中修改多個儲存格的值,然後在編輯模式中按 ESC 鍵兩次及在編輯模式之外按 ESC 鍵一次,以將整個資料列還原成其原始值。 當您在控制項中修改、加入或刪除資料列時,也會修改、加入和刪除資料存放區中的 Customer 物件。

後續步驟

這個應用程式提供您對事件的基本認識,您必須處理這些事件以便在 DataGridView 控制項中實作虛擬模式。 您可以用一些方式來改進這個基本應用程式:

  • 實作快取來自外部資料庫資料的資料存放區。 此快取區必須依需要擷取和捨棄值,因此它只會包含顯示所需的內容,並耗用用戶端電腦上非常少量的記憶體。

  • 依照您的需求,微調資料存放區的效能。 例如,您可能會使用較大的快取區大小,並將資料庫查詢的數目減到最少,來彌補緩慢的網路連接,而不要限制用戶端電腦的記憶體。

如需從外部資料庫快取值的詳細資訊,請參閱 HOW TO:在 Windows Form DataGridView 控制項中以 Just-In-Time 資料載入方式實作虛擬模式

請參閱

工作

HOW TO:在 Windows Form DataGridView 控制項中實作虛擬模式

參考

DataGridView

VirtualMode

CellValueNeeded

CellValuePushed

NewRowNeeded

RowValidated

RowDirtyStateNeeded

CancelRowEdit

UserDeletingRow

概念

縮放 Windows Form DataGridView 控制項的最佳作法

在 Windows Form DataGridView 控制項中以 Just-In-Time 資料載入方式實作虛擬模式

其他資源

Windows Form DataGridView 控制項中的效能微調