![]() |
Desktop Development »
Grid & Data Controls »
Grid controls
License: The Code Project Open License (CPOL)
Fast gridviewBy David ZenouA 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
|
||||||||||
|
Advanced Search Add to IE Search |
|
|
|
||||||||||||||||
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.
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 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
}
I learned how to extend a complex control like gridview.
If you have some improvement , i'm open to listen them
| You must Sign In to use this message board. | |||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||
General
News
Question
Answer
Joke
Rant
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 Web17 | Advertise on the Code Project |