다음을 통해 공유


연습: Windows Forms DataGridView 컨트롤에서 가상 모드 구현

표 형식의 대용량 데이터를 DataGridView 컨트롤에 표시하려는 경우 VirtualMode 속성을 true로 설정하고 컨트롤과 해당 데이터 저장소의 상호 작용을 명시적으로 관리할 수 있습니다. 이 방법을 사용하면 이 상황에서 컨트롤의 성능을 세밀하게 조정할 수 있습니다.

DataGridView 컨트롤은 사용자 지정 데이터 저장소와 상호 작용하기 위해 처리할 수 있는 여러 가지 이벤트를 제공합니다. 이 연습에서는 이러한 이벤트 처리기를 구현하는 과정을 보여 줍니다. 이 항목의 코드 예제에서는 매우 간단한 데이터 소스를 사용합니다. 프로덕션 설정에서는 일반적으로 표시해야 하는 행만 캐시에 로드한 다음 DataGridView 이벤트를 처리하여 캐시와 상호 작용하고 캐시를 업데이트합니다. 자세한 내용은 Windows Forms DataGridView 컨트롤에서 Just-In-Time 데이터 로드를 사용하여 가상 모드 구현를 참조하십시오.

이 항목의 코드를 단일 목록으로 복사하려면 방법: Windows Forms 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. DataGridView 컨트롤을 초기화하고 샘플 값으로 데이터 저장소를 채우는 폼의 Load 이벤트 처리기를 구현합니다.

    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. 요청된 셀 값을 데이터 저장소나 현재 편집 중인 Customer 개체에서 검색하는 CellValueNeeded 이벤트 처리기를 구현합니다.

    이 이벤트는 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. 편집 행을 나타내는 Customer 개체에 편집된 셀 값을 저장하는 CellValuePushed 이벤트 처리기를 구현합니다. 이 이벤트는 사용자가 셀 값 변경을 커밋할 때마다 발생합니다.

    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. 새로 만들어진 행을 나타내는 새 Customer 개체를 만드는 NewRowNeeded 이벤트 처리기를 구현합니다.

    이 이벤트는 사용자가 새 레코드에 대한 행을 입력할 때마다 발생합니다.

    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. 사용자가 Esc 키를 편집 모드에서 두 번 누르거나 편집 모드 이외의 모드에서 한 번 눌러 행 되돌리기 신호를 보내는 경우 CancelRowEdit 이벤트가 발생하는지 여부를 나타내는 RowDirtyStateNeeded 이벤트 처리기를 구현합니다.

    기본적으로 CancelRowEditRowDirtyStateNeeded 이벤트 처리기에서 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. 현재 행을 나타내는 Customer 개체의 값을 삭제하는 CancelRowEdit 이벤트 처리기를 구현합니다.

    이 이벤트는 사용자가 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. 기존 Customer 개체를 데이터 저장소에서 삭제하거나 새로 만들어진 행을 나타내는 저장되지 않은 Customer 개체를 삭제하는 UserDeletingRow 이벤트 처리기를 구현합니다.

    이 이벤트는 사용자가 행 머리글을 클릭하고 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 컨트롤에서 가상 모드를 구현하기 위해 처리해야 하는 이벤트에 대한 기본적인 이해를 제공합니다. 다양한 방법으로 이 기본 응용 프로그램을 향상시킬 수 있습니다.

  • 외부 데이터베이스의 값을 캐시하는 데이터 저장소를 구현합니다. 이 캐시는 클라이언트 컴퓨터의 메모리를 적게 소비하면서 표시해야 할 내용만 포함할 수 있도록 필요에 따라 값을 검색하고 삭제할 수 있어야 합니다.

  • 요구 사항에 따라 데이터 저장소의 성능을 세밀하게 조정합니다. 예를 들어, 캐시 크기를 크게하고 데이터베이스 쿼리 수를 최소화하여 클라이언트 컴퓨터 메모리를 제한하기 보다는 네트워크 연결 부하를 줄여야 할 수 있습니다.

외부 데이터베이스의 값을 캐시하는 방법에 대한 자세한 내용은 방법: Windows Forms DataGridView 컨트롤에서 Just-In-Time 데이터 로드를 사용하여 가상 모드 구현을 참조하십시오.

참고 항목

작업

방법: Windows Forms DataGridView 컨트롤에서 가상 모드 구현

참조

DataGridView

VirtualMode

CellValueNeeded

CellValuePushed

NewRowNeeded

RowValidated

RowDirtyStateNeeded

CancelRowEdit

UserDeletingRow

개념

Windows Forms DataGridView 컨트롤의 크기를 조정하는 최선의 방법

Windows Forms DataGridView 컨트롤에서 Just-In-Time 데이터 로드를 사용하여 가상 모드 구현

기타 리소스

Windows Forms DataGridView 컨트롤의 성능 조정