Click here to Skip to main content
6,306,412 members and growing! (16,307 online)
Email Password   helpLost your password?
Desktop Development » Grid & Data Controls » Grid controls License: The Code Project Open License (CPOL)

Fast gridview

By David Zenou

A Fast GridView optimized
C# (C# 1.0, C# 2.0, C# 3.0), Javascript, HTML, .NET (.NET 2.0, .NET 3.0, .NET 3.5), ASP.NET, Ajax
Posted:27 Oct 2008
Updated:4 Nov 2008
Views:9,566
Bookmarked:36 times
Unedited contribution
Announcements
Loading...
 
Search    
Advanced Search
printPrint   Broken Article?Report       add Share
  Discuss Discuss   Recommend Article Email
3 votes for this article.
Popularity: 1.91 Rating: 4.00 out of 5
1 vote, 33.3%
1

2

3

4
2 votes, 66.7%
5

Sample Image - maximum width is 600 pixels

Introduction

The GridView control is a very powerful and scalable .net control. You use it inside some application to list entites. However , there is a disadvantage when you want to use the Paging implementation : you must systematically bind the gridview with a select of all data when you change the index to see the other pages. So Imagine that you must work with a datasource with 400 000 records : the postback is expensive , the treatment is not optimized.

Background

I tryed to imagin an implementation solution with a gridview and an independant paging functionnality. The purpose is just to bind the gridview with the current datarows that you see. Sql server allow you to get a part of rows of a query with this syntaxe :

With Prod AS 
( SELECT [ProductID], 
		 [ProductName], 
		 [SupplierID], 
		 [CategoryID], 
		 [QuantityPerUnit], 
		 [UnitPrice], 
		 [UnitsInStock], 
		 [UnitsOnOrder], 
		 [ReorderLevel], 
		 [Discontinued] ,  
		 ROW_NUMBER() OVER (order by ProductName) as RowNumber from Products )
		 SELECT [ProductID], 
		[ProductName], 
		[SupplierID], 
		[CategoryID], 
		[QuantityPerUnit], 
		[UnitPrice], 
		[UnitsInStock], 
		[UnitsOnOrder], 
		[ReorderLevel], 
		[Discontinued] from Prod  Where RowNumber 
Between @pBegin and @pEnd 

I serach on Codeproject if a similar solution existed , and i found a source code whose implemented a very good smart pager. You can find it at : http://www.codeproject.com/KB/aspnet/SmartPager.aspx. So i extend the Gridview class to create GridviewPager class whose own a instance of this SmartPager control. The smart pager control is a complex type property (it has several property) so the pager class must implement IStateManager Interface , and a event to know when the index change

The implementation of the smart pager generate a inconvegnient postback in javascript (method SmartPagerSelectPage of Smartpager.js) when the index change so 2 postback are executed. To resolve this problem i parsed all the request form keys to find CALLBACKPARAM value in order to filter the bad post back , and just executing the good in GridviewPager Page_Load event.

Using the Code

using System;
using System.Net;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using Avg.Controls;
/// <summary>
/// Summary description for GridViewExtender
/// </summary>
/// 
namespace Avg.Controls
{
    public delegate void DataSourceChangedEventHandler(object sender, bool isEmpty);

    [ToolboxData("<{0}:GridViewPager runat="server">")]
public class GridViewPager : GridView
{
    /// <summary>
    /// Handling when the DataSourceChange
    /// </summary>
    public event DataSourceChangedEventHandler DataSourceChanged;

    /// <summary>
    /// A readonly unique ID for the current view.
    /// </summary>
    public string CurrentViewID
    {
        get { return string.Concat("CurrentView_", UniqueID); }
    }

    /// <summary>
    /// Overrides the data source property, so that we get a chance to test whether
    /// the source
    /// being bound contains data or not.
    ///
    /// This is used to communicate with the pager so that for an empty list no
    /// pager is shown.
    /// </summary>
    public override object DataSource
    {
        get
        {
            if (ViewState[CurrentViewID] != null)
                return ViewState[CurrentViewID];
            else
                return base.DataSource;

        }
        set
        {

            base.DataSource = value;
            ViewState[CurrentViewID] = value;


            if (value == null)
            {
                if (DataSourceChanged != null)
                    DataSourceChanged(this, true);
            }
            else
            {
                if (DataSourceChanged != null)
                    DataSourceChanged(this, false);
            }
        }
    }

    /// <summary>
    /// Smart Pager
    /// </summary>
    protected SmartPager pager;

    /// <summary>
    /// Numero of Page cliked
    /// </summary>
    public int PageNumberCliked
    {
        get { return (ViewState["PageNumberCliked"] == null) ? 1 : Int32.Parse(
            ViewState["PageNumberCliked"].ToString()); }
        set { ViewState["PageNumberCliked"] = value; }
    }


    /// <summary>
    /// Display pager numeros grouped by  Display value before '...' buton
    /// </summary>
    public int Display
    {
        get { return pager.Display; }
        set { pager.Display = value; }
    }

    /// <summary>
    /// Current first row to display
    /// </summary>
    public int rowB
    {
        get { return (Page.Session["rowB"] == null) ? 0 : Int32.Parse(
            Page.Session["rowB"].ToString()); }
        set { Page.Session["rowB"] = value; }
    }

    /// <summary>
    /// Current end row to display
    /// </summary>
    public int rowE
    {
        get { return (Page.Session["rowE"] == null) ? PageSize : Int32.Parse(
            Page.Session["rowE"].ToString()); }
        set { Page.Session["rowE"] = value; }
    }

    /// <summary>
    /// Calculate Page Count
    /// </summary>
    public int PageCount
    {
        get
        {

            if (RowCount == 0)
            {
                return PageSize;
            }

            if (this.DataSource == null)
            {
                throw new Exception("Datasource is empy");
            }

            if (PageSize == 0)
            {
                throw new Exception("Page size must be positive");
            }

            return (int)(RowCount / PageSize) + 1;


        }
    }

    /// <summary>
    /// Calculate Row Count
    /// </summary>
    public int RowCount
    {
        get { return (Page.Session["RowCount"] == null) ? 5 : Int32.Parse(
            Page.Session["RowCount"].ToString()); }
        set { Page.Session["RowCount"] = value; }
    }

    /// <summary>
    /// Current Page
    /// </summary>
    public int CurrentPage
    {
        get { return (ViewState["CurrentPage"] == null) ? 1 : Int32.Parse(
            ViewState["CurrentPage"].ToString()); }
        set { ViewState["CurrentPage"] = value; }
    }

    /// <summary>
    /// Constructor
    /// </summary>
public GridViewPager() : base()
{

    pager = new SmartPager();
    pager.OnClickEvent += new OnClickPagerNumberEventHandler(pager_OnClickEvent);

}

#region events to implement on the page side

private static readonly object OnSelectRowEventKey = new object();
/// <summary>
/// This events must be implemented with a select statement to get rows
/// </summary>
public event EventHandler DoSelectRow
{
    add { Events.AddHandler(OnSelectRowEventKey, value); }
    remove { Events.RemoveHandler(OnSelectRowEventKey, value); }
}

protected virtual void OnSelectedRow(EventArgs e)
{
    EventHandler handler = Events[OnSelectRowEventKey] as EventHandler;

    if (handler != null)
        handler(this, e);
    else
        throw new Exception("You must implement OnSelectRow method");
}

private static readonly object OnLoadRowCountEventKey = new object();
/// <summary>
/// This events must be implemented to know the row count
/// </summary>
public event EventHandler DoLoadRowCount
{
    add { Events.AddHandler(OnLoadRowCountEventKey, value); }
    remove { Events.RemoveHandler(OnLoadRowCountEventKey, value); }
}

protected virtual void OnLoadedRowCount(EventArgs e)
{
    EventHandler handler = Events[OnLoadRowCountEventKey] as EventHandler;

    if (handler != null)
        handler(this, e);
    else
        throw new Exception("You must implement OnLoadRowCount method");
}


#endregion events to implement on the page side


#region Component event

/// <summary>
/// OnInit Event
/// </summary>

protected override void OnInit(EventArgs e) 
{ 
    base.OnInit(e); Page.Load += new EventHandler(Page_Load); 
}
/// <summary>
/// PageLoad Event 
/// </summary>
void Page_Load(object sender, EventArgs e) 
{ 
    if (!Page.IsPostBack) OnLoadedRowCount(EventArgs.Empty); 
    bool goodCall = true; //the current page is posted 2 times : 
    // 1- in javascript SmartPager.js by SmartPagerSelectPage when a new page
    // is clicked (with callback parameter) 
    // 2- on the pager_OnClickEvent (without callback parameter) 
    foreach (string Key in Page.Request.Form.AllKeys) 
    {
        if (Key.EndsWith("CALLBACKPARAM")) 
        { 
            goodCall = false; 
        } 
    } 
    //Handle just one time after pager_OnClickEvent call when the CALLBACKPARAM is missing 
    if (goodCall) 
        OnSelectedRow(EventArgs.Empty); 
} 
/// <summary>
/// Load the Control 
/// </summary>
protected override void OnLoad(EventArgs e) 
{ 
    base.OnLoad(e); Controls.Add(pager); 
} 
/// <summary>
/// PreRender the Control 
/// </summary>
protected override void OnPreRender(EventArgs e) 
{ 
    base.OnPreRender(e); 
    pager.PageCount = PageCount; 
}
/// <summary>
/// Event Handler Click Page with ICallBackEventHandler in SmartPager 
/// </summary>
void pager_OnClickEvent(object sender, string pPageNum) 
{
    PageNumberCliked = Int32.Parse(pPageNum); 
    CurrentPage = PageNumberCliked; 
    if (CurrentPage == 1) 
    { 
        rowB = 0; 
        rowE = PageSize; 
    } 
    else 
    { 
        rowE = (PageSize * CurrentPage) - 1;
        rowB = rowE - (PageSize - 1);
    }
    //Call postabck without call back parameters
    Page.Response.Write( "<script language="Javascript">__doPostBack('__Page', 'MyCustomArgument');</script>" ); 
} 
#endregion Component event 
#region IStateManager Members 
/// <summary>
/// Load the ViewState 
/// </summary>
protected override void LoadViewState(object savedState) 
{ 
    if (savedState != null) 
    { 
        object[] state = savedState as object[]; 
        if (state != null && state.Length == 2) 
        { 
            base.LoadViewState(state[0]); 
            if (state[1] != null) 
                ((IStateManager)this.pager).LoadViewState(state[1]); 
        } 
    } 
    else
        base.LoadViewState(savedState); 
} 
/// <summary>
/// Save the ViewState 
/// </summary>
protected override object SaveViewState() 
{ 
    object[] state = new object[2];
    state[0] = base.SaveViewState();
    if (pager != null) 
        state[1] = ((IStateManager)this.pager).SaveViewState(); 
    return state; 
} 
/// <summary>
/// Track the Viewstate 
/// </summary>
protected override void TrackViewState() 
{ 
    base.TrackViewState(); 
    if (pager != null) 
        ((IStateManager)this.pager).TrackViewState(); 
} 
#endregion 
}

Points of Interest

I learned how to extend a complex control like gridview.

History

If you have some improvement , i'm open to listen them

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

David Zenou


Member
I am a new Fan of dotnet technologies. I began to work with Java j2ee technologies and today i made my choice : .Net Framework is very pleasant , has excellents article codes and documentation. I work in a insurance company with .NET 2.0 Framework (Asp.net and windows forms).
I found very useful articles in codeproject , and today i want to give my contribution , and i hope that my articles will be useful.
Occupation: Software Developer
Company: Several
Location: France France

Other popular Grid & Data Controls articles:

Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 6 of 6 (Total in Forum: 6) (Refresh)FirstPrevNext
Generalclick Page Numer "1" and "2" produce same result. what is wrong ? [modified] Pinmembervrajaramanv18:55 15 Jan '09  
RantThe Download Link also NAVER wrok! PinmemberMr.Crhan20:52 29 Oct '08  
GeneralRe: The Download Link also NAVER wrok! PinmemberDavid Zenou3:33 4 Nov '08  
GeneralRe: The Download Link also NAVER wrok! PinmemberMr.Crhan16:32 25 Nov '08  
GeneralThe download link doesn't work PinmemberScott Bruno9:57 29 Oct '08  
GeneralRe: The download link doesn't work PinmemberDavid Zenou3:34 4 Nov '08  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 4 Nov 2008
Editor: Sean Ewington
Copyright 2008 by David Zenou
Everything else Copyright © CodeProject, 1999-2009
Web09 | Advertise on the Code Project