DevTrain

Autor: Tobi Ulm

Paging mit der PagedDataSource Klasse

Einer der wesentlichsten Vorteile des neuen ASP .net Web Server Controls DataGrid, ist die eingebaute Pagingfuntkionalität. Leider ist das DataGrid jedoch sehr unflexibel, was das Formatieren der Ergebnismenge betrifft und deshalb ist an dieser Stelle das DataList Control die bessere Wahl. Nur leider wird der ungeübte ASP .net Entwickler innerhalb von Visual Studio .net eine AllowPaging Property des DataGrid's bei dem DataList Control schmerzlich vermissen. Nun beginnen hier einige Programmierer und Buchautoren über skurrile Indexwerte und SQL Abfragen die zur Ansicht benötigten Datensätze aus der Datenbankquelle zu filtern. Warum nicht die eingebauten Tool's des .net Frameworks benutzen? Abhilfe schafft hier die PagedDataSource Klasse im System.Web.UI.WebControls Namespace. Die Klasse ist die Grundlage für das Paging innerhalb des DataGrid Controls und ist gedacht für Control Entwickler. Die Klasse versucht dabei auf die bestmögliche Art und Weise die Daten der aktuellen Seite zu ermitteln. Die beiden schnellsten Möglichkeiten sind hier zu erwähnen, die System.Array Klasse und das System.Collections.IList Interface, denn damit unterstützt die Datenquelle einen Indexunterstützen Zugriff. Bietet die Datenquelle keinen der beiden Indexzugriffe, verwendete die PagedDataSource Klasse das Interface System.Collections.IEnumerable, welches unteranderem die Grundlage für den altbekannten ForEach VB Konstrukt ist.
In meinem Beispiel verwende ich ein DataList Control und eine DataTable Instanz. Die DataTable verwende ich, da ich mir damit den Overhead des DataSet Objektes spare. Folgende Vorgehensweise ist im Quellcode zu finden:
- Erzeugen einer Connection [ connSQL ]
- Erzeugen eines SQL Commands [ cmdCustomers ]
- Erzeugen eines Data Adapters [ daCustomers ]
- Öffnen der Connection
- Füllen der DataTable [dtReturn]
SqlConnection connSQL = new SqlConnection("Server=(local);Database=Northwind;UID=sa;PWD=");
SqlCommand cmdCustomers = new SqlCommand("SELECT * FROM Customers", connSQL);
SqlDataAdapter daCustomers = new SqlDataAdapter(cmdCustomers);
DataTable dtReturn = new DataTable();

Soweit zum Standardvorgang, nun kommt der eigentliche Trick. Ich erzeuge eine Objektinstanz von PagedDataSource [ myList ] und weise den DefaultView der DataTable zu. Danach stelle ich im Objekt myList folgende Properties ein:
- myList.AllowPaging = true; Einschalten des Pagings
- myList.PageSize = 10; Wie viele Datensätze sollen pro Page angezeigt werden?
Wichtig ist dann die Property [ myList.CurrentPageIndex ], diese gibt dem PagedDataSource Objekt die Seite an, welche die Daten enthält die nun angezeigt werden sollen. Ich verwende hier das ViewState Objekt um die Werte zwischenzuspeichern, genauso könnten sie hier die URL oder die Session Objekt verwenden.
Danach binde ich die PagedDataSource [ myList ] als Datenquelle des DataList Objektes.

connSQL.Open();
daCustomers.Fill(dtReturn);
connSQL.Close();
connSQL.Dispose();
System.Web.UI.WebControls.PagedDataSource myList = new System.Web.UI.WebControls.PagedDataSource();
myList.DataSource = dtReturn.DefaultView;
myList.AllowPaging = true;
myList.PageSize = 10;
if(!Page.IsPostBack){ViewState["dlCount"] = myList.PageCount-1;}
myList.CurrentPageIndex = (int)ViewState["dlActionFilterPageCount"];
DataList1.DataSource = myList;
DataList1.DataBind();

Zum Schluss werden noch die Eventhandler der Navigationsbuttons gesetzt. Dies ist jedoch recht einfache gehalten. Ich setzte den ViewState-Counter auf den entsprechenden Wert, also zum Beispiel auf 0 für die erste Paging Seite, danach muss der Datenabholvorgang wieder durchgeführt werden.

private void btnFirst_Click(object sender, System.EventArgs e) {
 ViewState["dlActionFilterPageCount"] = 0;
 RetrieveData();
}

private void btnLast_Click(object sender, System.EventArgs e) {
 ViewState["dlActionFilterPageCount"] = (int)ViewState["dlCount"];
 RetrieveData();
}

private void btnNext_Click(object sender, System.EventArgs e) {
 ViewState["dlActionFilterPageCount"] = ((int)ViewState["dlActionFilterPageCount"]) + 1;
 RetrieveData();
}

private void btnPrev_Click(object sender, System.EventArgs e) {
 ViewState["dlActionFilterPageCount"] = ((int)ViewState["dlActionFilterPageCount"]) - 1;
 RetrieveData();
}


Der UI QuellCode:

<%@ Page language="c#" Codebehind="adoPagedDataSource.aspx.cs" AutoEventWireup="false" Inherits="DevTrain_Artikel.adoPagedDataSource" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML>
  <HEAD>
    <title>adoPagedDataSource</title>
    <meta name="GENERATOR" Content="Microsoft Visual Studio 7.0">
    <meta name="CODE_LANGUAGE" Content="C#">
    <meta name=vs_defaultClientScript content="JavaScript">
    <meta name=vs_targetSchema content="http://schemas.microsoft.com/intellisense/ie5">
  </HEAD>
  <body >
 
    <form id="adoPagedDataSource" method="post" runat="server">
<asp:DataList id="DataList1" runat="server" BorderStyle="Ridge">
<HeaderTemplate>
 <table>
</HeaderTemplate>
<ItemTemplate>
 <tr>
  <td rowspan="2">
   evtl. BILD
  </td>
  <td>
   <%# DataBinder.Eval(Container.DataItem, "CustomerID")%>
  </td>
  <td>
   <%# DataBinder.Eval(Container.DataItem, "PostalCode")%>
  </td>
  <td>
   <%# DataBinder.Eval(Container.DataItem, "City")%>
  </td>
  <td>
   <%# DataBinder.Eval(Container.DataItem, "Country")%>
  </td>
 </tr>
 <tr>
  <td>
   <%# DataBinder.Eval(Container.DataItem, "ContactName")%>
  </td>
 </tr>
</ItemTemplate>
<FooterTemplate>
 </table>
</FooterTemplate>
</asp:DataList><br>
<asp:Button id="btnFirst" runat="server" Text="|<" BorderStyle="Ridge"></asp:Button>
<asp:Button id="btnPrev" runat="server" Text="<<" BorderStyle="Ridge"></asp:Button>
<asp:Button id="btnNext" runat="server" Text=">>" BorderStyle="Ridge"></asp:Button>
<asp:Button id="btnLast" runat="server" Text=">|" BorderStyle="Ridge"></asp:Button>

     </form>
 
  </body>
</HTML>

Der CodeBehind

using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;

namespace DevTrain_Artikel
{
 /// <summary>
 /// Summary description for adoPagedDataSource.
 /// </summary>
 public class adoPagedDataSource : System.Web.UI.Page
 {
  protected System.Web.UI.WebControls.Button btnFirst;
  protected System.Web.UI.WebControls.Button btnPrev;
  protected System.Web.UI.WebControls.Button btnNext;
  protected System.Web.UI.WebControls.Button btnLast;
  protected System.Web.UI.WebControls.DataList DataList1;
  
  private void Page_Load(object sender, System.EventArgs e)
  {
   // Put user code to initialize the page here
   //
   if(!Page.IsPostBack){
    ViewState["dlActionFilterPageCount"] = 0;
    RetrieveData();
   }
  }
  //function to get Data from SQL Server DataBase Northwind
  private void RetrieveData() {
   SqlConnection connSQL = new SqlConnection("Server=(local);Database=Northwind;UID=sa;PWD=");
   SqlCommand cmdCustomers = new SqlCommand("SELECT * FROM Customers", connSQL);
   SqlDataAdapter daCustomers = new SqlDataAdapter(cmdCustomers);
   DataTable dtReturn = new DataTable();
   try {
    connSQL.Open();
    daCustomers.Fill(dtReturn);
    connSQL.Close();
    connSQL.Dispose();
    System.Web.UI.WebControls.PagedDataSource myList = new System.Web.UI.WebControls.PagedDataSource();
    myList.DataSource = dtReturn.DefaultView;
    myList.AllowPaging = true;
    myList.PageSize = 10;
    if(!Page.IsPostBack){ViewState["dlCount"] = myList.PageCount-1;}
    myList.CurrentPageIndex = (int)ViewState["dlActionFilterPageCount"];
    DataList1.DataSource = myList;
    DataList1.DataBind();
   }
   catch (Exception eXP ) {
    Response.Write("<font color='red'>Fehler: " + eXP.ToString() + "</font>");

   }
  }

  #region Web Form Designer generated code
  override protected void OnInit(EventArgs e)
  {
   //
   // CODEGEN: This call is required by the ASP.NET Web Form Designer.
   //
   InitializeComponent();
   base.OnInit(e);
  }
  
  /// <summary>
  /// Required method for Designer support - do not modify
  /// the contents of this method with the code editor.
  /// </summary>
  private void InitializeComponent()
  {   
   this.btnFirst.Click += new System.EventHandler(this.btnFirst_Click);
   this.btnPrev.Click += new System.EventHandler(this.btnPrev_Click);
   this.btnNext.Click += new System.EventHandler(this.btnNext_Click);
   this.btnLast.Click += new System.EventHandler(this.btnLast_Click);
   this.Load += new System.EventHandler(this.Page_Load);

  }
  #endregion

  private void btnFirst_Click(object sender, System.EventArgs e) {
   ViewState["dlActionFilterPageCount"] = 0;
   RetrieveData();
  }

  private void btnLast_Click(object sender, System.EventArgs e) {
   ViewState["dlActionFilterPageCount"] = (int)ViewState["dlCount"];
   RetrieveData();
  }

  private void btnNext_Click(object sender, System.EventArgs e) {
   ViewState["dlActionFilterPageCount"] = ((int)ViewState["dlActionFilterPageCount"]) + 1;
   RetrieveData();
  }

  private void btnPrev_Click(object sender, System.EventArgs e) {
   ViewState["dlActionFilterPageCount"] = ((int)ViewState["dlActionFilterPageCount"]) - 1;
   RetrieveData();
  }
 }
}


Erfasst am: 05.08.2002 - Artikel-URL: http://www.devtrain.de/news.aspx?artnr=793
© Copyright 2003 ppedv AG - http://www.ppedv.de