Поделиться через


Пример. Реализация виртуального режима для элемента управления DataGridView в Windows Forms

Если в элементе управления DataGridView требуется отобразить большой объем табличных данных, можно задать для свойства VirtualMode значение true и явным образом управлять взаимодействием элемента управления с хранилищем данных. Это позволяет управлять производительностью элемента управления в такой ситуации.

Элемент управления DataGridView предоставляет несколько событий, которые могут обрабатываться для взаимодействия с пользовательским хранилищем данных. Процесс реализации таких обработчиков событий описан в данном пошаговом руководстве. В примере кода в этом разделе для наглядности используется очень простой источник данных. На практике обычно загружаются только строки, необходимые для отображения в кэше, а события DataGridView обрабатываются для взаимодействия с кэшем и его обновления. Дополнительные сведения содержатся в разделе Реализация виртуального режима с JIT-загрузкой данных для элемента управления DataGridView в Windows Forms.

Чтобы скопировать весь текст кода из этой темы, см. ссылку Практическое руководство. Реализация виртуального режима для элемента управления DataGridView в Windows Forms.

Создание формы

Чтобы реализовать виртуальный режим

  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, который указывает, будет ли происходить событие CancelRowEdit в случае, если пользователь восстанавливает строку, нажав ESC два раза в режиме редактирования или один раз в другом режиме.

    По умолчанию CancelRowEdit происходит при восстановлении строки, если любые ячейки в текущей строке были изменены, за исключением случая, когда для свойства QuestionEventArgs.Response задано значение true в обработчике событий RowDirtyStateNeeded. Это событие наиболее эффективно, если область фиксации определяется во время выполнения.

    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 два раза в режиме редактирования или один раз в другом режиме. Это событие не происходит, если ячейки в текущей строке не были изменены или для свойства QuestionEventArgs.Response было задано значение false в обработчике событий 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;
        }
    }
    
       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 два раза в режиме редактирования или один раз в другом режиме. При изменении, добавлении или удалении строк в элементе управления, также изменяются, добавляются или удаляются объекты Customer в хранилище данных.

Следующие действия

Это приложение позволяет в общем понять, какие события необходимо обработать для реализации виртуального режима в элементе управления DataGridView. Это основное приложение можно улучшить несколькими способами.

  • Реализуйте хранилище данных, кэширующее значения из внешней базы данных. Кэш извлекает и отменяет значения по мере необходимости таким образом, что в нем содержатся только необходимые для отображения данные — при этом сокращается потребление ресурсов памяти на клиентском компьютере.

  • Выполните точную настройку производительности хранилища данных в зависимости от конкретных требований. Например, может потребоваться компенсировать медленное сетевое соединение, а не ограничения оперативной памяти компьютера клиента. В таком случае можно использовать кэш с увеличенным размером, чтобы свести к минимуму количество запросов к базе данных.

Дополнительные сведения о кэшировании значений из внешней базы данных содержатся по ссылке Практическое руководство. Реализация виртуального режима с JIT-загрузкой данных для элемента управления DataGridView в Windows Forms.

См. также

Задачи

Практическое руководство. Реализация виртуального режима для элемента управления DataGridView в Windows Forms

Ссылки

DataGridView

VirtualMode

CellValueNeeded

CellValuePushed

NewRowNeeded

RowValidated

RowDirtyStateNeeded

CancelRowEdit

UserDeletingRow

Основные понятия

Масштабирование элемента управления DataGridView в Windows Forms

Реализация виртуального режима с JIT-загрузкой данных для элемента управления DataGridView в Windows Forms

Другие ресурсы

Оптимизация производительности элемента управления DataGridView в Windows Forms