Glengamoi (Forum) · AspHeute · .NET Heute (RSS-Suche) · AspxFiles (Wiki) · .NET Blogs

Pager- und Footerzeilen des DataGrid erweitern

Geschrieben von: Alexander Zeitler
Kategorie: .NET Fu

This printed page brought to you by AlphaSierraPapa

Der Pager des DataGrids bietet standardmäßig nur zwei Arten der Formatierung: Seitenzahlen und "Symbole" zum Blättern ohne Angabe der Seitenzahlen. Ähnlich langweilig gestaltet sich der Footer - im Normalfall ist er nämlich leer, obwohl er sich gerade bei DataGrids für zB Summierung einzelner Spalten eignet.

Die in diesem .NET Fu vorgestellte Lösung wird so aussehen:

Die Lösung: Pager

Anwenderfreundlicher wäre ein Pager schon alleine durch die Tatsache, daß vor den Seitenzahlen das Wort "Seite" erscheint, damit der User überhaupt weiß, daß es sich um einen Pager mit mehreren Ergebnisseiten handelt.

Die Umsetzung ist relativ einfach. Ausgehend von der Tatsache, daß das Paging im DataGrid mittels AllowPaging bereits aktiviert ist, brauchen wir nur eine Möglichkeit, HTML-Elemente bzw. Text in den erzeugten DataGrid-HTML-Output einzubauen. Hierzu bietet sich das Event OnItemCreated unseres DataGrids an - idealerweise müssen wir uns hierbei nicht einmal durch HTML-Code wühlen, sondern bekommen eine einfach zu bearbeitende Control-Collection. Die Umsetzung ist jetzt fast nur noch Formsache:

private void ItemCreated(object sender, DataGridItemEventArgs e)
{
  if(e.Item.ItemType==ListItemType.Pager)
  {
    Label lblPager = new Label();
    lblPager.Text = "Seite " + lblPager.Text;
    e.Item.Controls[0].Controls.AddAt(0,lblPager);
  }
}

Nach einer Prüfung, ob das aktuelle Item der Pager ist, setzen wir einfach einen neuen Label an den Anfang der Controls-Collection des Pagers, welcher den Text "Seite:&nbsp" beinhaltet. Direkt im Anschluß an diesen folgen die Label- und LinkButton-Controls, welche die Seitenzahlen ausgeben.

Die Lösung: Footer

Wie eingangs bereits erwähnt, ist der Footer standardmäßig zum einen leer und zum anderen auch deaktiviert. Letzteres ändern wir sofort durch ein

this.DataGrid1.ShowFooter = true;

Den jetzt gewonnen freien Platz nutzen wir, um die Abfrage "Product Sales for 1995" aus der bekannten "Northwind"-Datenbank im DataGrid über mehrere Seiten verteilt darzustellen und an jedem Seitenende - eben in jenem Footer - den Übertrag der jeweiligen Umsätze für diese Seite darzustellen. Außerdem erweitern wir die Lösung noch dahingehend, daß wir auf der letzten Seite die Gesamtsumme präsentieren.

Die Herangehensweise ist ähnlich wie beim Pager, allerdings nutzen wir hier das Event OnItemDataBound.

Der erste Schritt ist die Generierung der Zwischensummen der einzelnen Seiten. Hierzu ist es notwendig, die Werte der einzelnen DataGridItems zu addieren. Zunächst ist also zu prüfen, ob das aktuelle Item ein Item bzw. AlternatingItem darstellt. Ist dies der Fall, werden die Werte aus der Datenquelle anhand des DataSetIndex' des aktuellen Items gelesen:

private void ItemDataBound(object sender, DataGridItemEventArgs e)
{
 if((e.Item.ItemType==ListItemType.Item)||(e.Item.ItemType==ListItemType.AlternatingItem))
 {
   lumpSum += 
      Double.Parse((this.ReadDataFromDB().Tables[0].Rows[e.Item.DataSetIndex][2].ToString()));
 }
}

"lumpSum" ist als öffentliche Variable vom Typ double innerhalb der Page-Klasse zu deklarieren:

public double lumpSum;

Der Weg über die Datenquelle erscheint zunächst umständlicher als z.B. die aktuellen Zellinhalte des DataGrids mittels Replace zu bearbeiten (in diesem Falle, um das Währungssymbol zu eliminieren) und zu addieren. Doch wie wir alle wissen, finden sich selten zwei Server mit absolut identischen Konfigurationen - die nächste Exception wegen fehlerhafter Inputstrings bei Double.Parse ist somit vorprogrammiert.

Nachdem wir nun die Summe ermittelt haben, müssen wir diese noch in die entsprechende Footerzelle des DataGrids schreiben. Diese Zellen lassen sich über einen nullbasierenten Index ansprechen. In unserem Fall handelt es sich um die dritte Spalte, somit wäre der gesuchte Index "2". Zu beachten ist hierbei, daß evtl. ausgeblendete Spalten (Visible=false) ebenfalls zu zählen sind. Die Zelle des Footers steht direkt als Objekt zur Verfügung und kann über die .Text-Eigenschaft den ermittelten und als Währung formatierten Wert von "lumpSum" aufnehmen (das Ganze findet nach wie vor in ItemDataBound statt).

if(e.Item.ItemType==ListItemType.Footer)
{
  e.Item.Cells[2].HorizontalAlign = HorizontalAlign.Right;
  e.Item.Cells[2].Text = "Übertrag: " + string.Format("{0:c}",lumpSum);
}

Schließlich fehlt uns nur noch die Ausgabe der Endsumme auf der letzten Seite. Hierzu müssen wir zunächst herausfinden, ob wir uns auf der letzten Seite befinden. Dies geschieht, indem wir die Anzahl der Datensätze in der Datenquelle durch die Seitengröße dividieren. Der Ganzzahlanteil stellt den Index der letzten Seite dar. Tritt der Sonderfall ein, daß der letzte Datensatz die letzte Seite genau ausfüllt, ist der Index um 1 zu minimieren, da sonst der Index eine Seite zuviel "produzieren" würde. Die wiederum würde dazu führen, daß auf unserer letzten Seite keine Endsumme erscheint.

Entspricht der ermittelte Index der letzten Seite "lastPageIndex" dem Index der aktuellen Seite, sind wir auf der letzten Seite gelandet. Jetzt müssen wir nur noch die Werte der Datenquelle aufsummieren und ähnlich wie beim Übertrag an unseren Footer anfügen:

DataSet dsSales = this.ReadDataFromDB();
int lastPageIndex = dsSales.Tables[0].Rows.Count/DataGrid1.PageSize;
if(dsSales.Tables[0].Rows.Count%DataGrid1.PageSize==0)
	lastPageIndex--;
if(lastPageIndex==DataGrid1.CurrentPageIndex)
{
	double totalLumpSum = 0;
	foreach(DataRow dr in this.ReadDataFromDB().Tables[0].Rows)
	{
		totalLumpSum += double.Parse(dr["ProductSales"].ToString());
	}
	e.Item.Cells[2].Text += 
		"<br>Endsumme:&nbsp;" + string.Format("{0:c}",totalLumpSum);
}

Somit ergibt sich für die hier vorgestellten Implementierungen im Gesamten also folgender Code (für den leichteren Überblick):

public double lumpSum;
private void ItemCreated(object sender, DataGridItemEventArgs e)
{
  if(e.Item.ItemType==ListItemType.Pager)
  {
    Label lblPager = new Label();
    lblPager.Text = "Seite&nbsp;" + lblPager.Text;
    e.Item.Controls[0].Controls.AddAt(0,lblPager);
  }
}

private void ItemDataBound(object sender, DataGridItemEventArgs e)
{
  if((e.Item.ItemType==ListItemType.Item)||(e.Item.ItemType==ListItemType.AlternatingItem))
  {
    lumpSum = lumpSum + 
     Double.Parse((this.ReadDataFromDB().Tables[0].Rows[e.Item.DataSetIndex][2].ToString()));
  }

  if(e.Item.ItemType==ListItemType.Footer)
  {
    e.Item.Cells[2].HorizontalAlign = HorizontalAlign.Right;
    e.Item.Cells[2].Text = "Übertrag:&nbsp;" + string.Format("{0:c}",lumpSum);
    DataSet dsSales = this.ReadDataFromDB();
    int lastPageIndex = dsSales.Tables[0].Rows.Count/DataGrid1.PageSize;
    if(dsSales.Tables[0].Rows.Count%DataGrid1.PageSize==0)
      lastPageIndex-- ;
    if(lastPageIndex==DataGrid1.CurrentPageIndex)
    {
      double totalLumpSum = 0;
      foreach(DataRow dr in this.ReadDataFromDB().Tables[0].Rows)
      {
        totalLumpSum += double.Parse(dr["ProductSales"].ToString());
      }
      e.Item.Cells[2].Text += 
        "<br>Endsumme:&nbsp;" + string.Format("{0:c}",totalLumpSum);
    }
  }
}

Ein funktionsfähiges Beispiel dieser Implementierung finden Sie hier.

Schlußbemerkung

Dieser Artikel hat gezeigt, wie leicht sich die scheinbar "statischen" Daten im DataGrid auch nachträglich modifizieren lassen. Natürlich bietet diese Implementierung Potential für weitere Verbesserungen - so werden Sie sicherlich die Daten aus Performancegründen nicht bei jedem Durchlauf von ItemDataBound aus der Datenbank lesen.

Eine weitere interessante Aufgabe, die auf dieser Lösung basiert, wäre beispielsweise den Übertrag der vorhergehenden Seiten mit dem Übertrag der aktuellen Seite zu kumulieren.

This printed page brought to you by AlphaSierraPapa

Download des Codes

Klicken Sie hier, um den Download zu starten.
http://www.aspheute.com/code/20040318.zip

Verwandte Artikel

Das ASP.NET DataGrid selbst erweitern
http:/www.aspheute.com/artikel/20030909.htm
DataGrid - Daten bearbeiten leicht gemacht
http:/www.aspheute.com/artikel/20040929.htm
Einträge numerieren im DataGrid
http:/www.aspheute.com/artikel/20040317.htm
MouseOver-Effekte beim DataGrid
http:/www.aspheute.com/artikel/20040628.htm
Vergleich von DataGrid, DataList und Repeater-Control - was verwende ich wann?
http:/www.aspheute.com/artikel/20040303.htm
Zahl, Datum und Währung korrekt formatiert ausgeben
http:/www.aspheute.com/artikel/20020704.htm

 

©2000-2006 AspHeute.com
Alle Rechte vorbehalten. Der Inhalt dieser Seiten ist urheberrechtlich geschützt.
Eine Übernahme von Texten (auch nur auszugsweise) oder Graphiken bedarf unserer schriftlichen Zustimmung.