Nutzung grosser Datenmengen beim DataGridView  
Frank Dzaebel, erstellt am: 9.4.2006, zuletzt geändert:  22.7.2010
Kategorie: DataGridView, .NET-Version: 2.0, [Download] [Download2]

Die VirtualMode-Eigenschaft des DataGridViews ist neu im .NET Framework 2.0. Hier ein etwas vereinfachtes Beispiel, um 200.000 Datensätze im DataGridView anzuzeigen. Es wird nur ein Ereignis behandelt: DataGridView.CellValueNeeded. Das Füllen der 200.000 Daten-Templates ins Grid dauert nur etwa 200 Millisekunden. In diesem Szenario sollte einer der "dataGridView1.Invalidate()" Methoden aufgerufen werden (ggf. InvalidateCell), wenn im DataTable Werte geändert werden, um diese im Grid anzuzeigen.

Eine Zelle aus dem Code heraus ändern
Eingaben vom User erlauben und anzeigen

Weiterführende Literatur (Beispiele):
    [Presenting Data with the DataGridView Control]
    [Empfohlene Vorgehensweisen für das Skalieren des DataGridView-Steuerelements in Windows Forms]



using System.Windows.Forms;
using System.Data;
using System;

namespace DataGvVirtual
{
  public partial class Form1 : Form
  {
    public Form1() {InitializeComponent();}

    const int initialSize = 200000;
    DataTable dt = new DataTable("Daten");
    private void btnFill_Click(object sender,EventArgs e)
    {
      dataGridView1.VirtualMode = true; Cursor = Cursors.WaitCursor;
      dataGridView1.CellValueNeeded += new DataGridViewCellValueEventHandler(dataGridView1_CellValueNeeded);
      dataGridView1.AllowUserToDeleteRows = false;
      dataGridView1.Columns.Clear(); dataGridView1.Rows.Clear();
      dataGridView1.Columns.Add("Name","Name");
      dataGridView1.Columns.Add("Reich","Reich");
      dataGridView1.Columns.Add("Neffen","Neffen");
      dataGridView1.Columns.Add("Geburtsdatum","Geburtsdatum");
      dataGridView1.Columns[3].DefaultCellStyle.Format = "dd.MMMM yyyy";
      dataGridView1.Rows.AddCopies(0,initialSize);
      dataGridView1.AllowUserToAddRows = false;
      dataGridView1.ReadOnly = true; Cursor = Cursors.Default;
    }

    private void dataGridView1_CellValueNeeded(object sender,DataGridViewCellValueEventArgs e)
    {
      e.Value = dt.Rows[e.RowIndex][e.ColumnIndex];
    }

    private void btnFillDataSource_Click(object sender,EventArgs e)
    {
      Cursor = Cursors.WaitCursor;
      dt.Columns.Clear(); dt.Rows.Clear();
      dt.Columns.Add(new DataColumn("Name"));
      dt.Columns.Add(new DataColumn("Reich",typeof(bool)));
      dt.Columns.Add(new DataColumn("Neffen",typeof(int)));
      dt.Columns.Add(new DataColumn("Geburtsdatum",typeof(DateTime)));
      DateTime date = DateTime.Now;
      for (int i = 0; i < initialSize; i++)
      {
        date = date.AddDays(1);
        AddNewRow(dt, "Donald"+i, true, 1, date);
      }
      Cursor = Cursors.Default; btnFill.Enabled = true;
    }

    private void AddNewRow(DataTable dt,string name,bool reich,int neffen,DateTime geburtsDatum)
    {
      DataRow dr = dt.NewRow();
      dr[0] = name; dr[1] = reich; dr[2] = neffen; dr[3] = geburtsDatum;
      dt.Rows.Add(dr);
    }
  }
}

Eine Zelle aus dem Code heraus ändern

Will man einer beliebigen Zelle im DataGridView bei aktiviertem VirtualMode einen Wert zuweisen, so muss man sich klarmachen, dass der Wert der Zelle über das CellValueNeeded-Ereignis geholt und gesetzt wird. Das Ereignis wird z.B. dann erzeugt, wenn die Zelle neu gezeichnet werden muss. Das kann man aber auch über die Invalidate-Methoden des DataGridView's manuell erwirken. In dem Augenblick benötigt die Grid-Zelle (zum Zeichnen) den Wert, es wird also CellValueNedded aufgerufen!

   private void button1_Click(object sender, EventArgs e)
   {
     dt.Rows[199000][0] = "Hallo!";
      dataGridView1.InvalidateCell(0, 199000);
   }



Eingaben vom User erlauben und anzeigen

Das obige Beispiel erlaubt zunächst wegen "ReadOnly=true" keine Eingaben. Will man dies gewährleisten, so nimmt man schlicht die "ReadOnly=true"-Zeile heraus, fügt folgenden Handler im btnFill_Click hinzu:

  dataGridView1.CellValuePushed += new DataGridViewCellValueEventHandler(dataGridView1_CellValuePushed); 

und implementiert das Ereignis so:

  void dataGridView1_CellValuePushed(object sender, DataGridViewCellValueEventArgs e)
  {
    dt.Rows[e.RowIndex][e.ColumnIndex] = e.Value;
  }