65.9K
CodeProject 正在变化。 阅读更多。
Home

快速 GridView

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.27/5 (5投票s)

2008年10月27日

CPOL

1分钟阅读

viewsIcon

50506

downloadIcon

627

一个快速且优化的 GridView。

Sample Image

引言

GridView 控制是一个非常强大且可扩展的 .NET 控制。您可以在应用程序中使用它来列出实体。但是,当您想要使用分页功能时,存在一个缺点:您必须系统地将 GridView 与所有数据的选择绑定,以便在更改索引时查看其他页面。想象一下,您必须使用一个包含 400,000 条记录的数据源:由于处理未优化,回发会非常耗费资源。

背景

我尝试提出一个 GridView 实现,该实现具有独立的分页功能。目的是将 GridView 与您看到的当前 DataRow 绑定。SQL Server 允许您使用以下语法获取查询的部分行:

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

我在 CodeProject 上搜索,看看是否存在类似的解决方案,我找到一个源代码,它实现了一个非常智能的分页器。您可以在这里找到它:https://codeproject.org.cn/KB/aspnet/SmartPager.aspx。我扩展了 GridView 类以创建 GridviewPager 类,该类拥有此 SmartPager 控制的实例。SmartPager 控制是一个*复杂类型属性(它具有多个属性)*,因此分页器类必须实现 IStateManager 接口和一个事件,以了解索引何时更改。

智能分页器的实现会在 JavaScript 中生成一个不便的回发(Smartpager.jsSmartPagerSelectPage 方法),当索引更改时会执行两个回发。为了解决这个问题,我解析了所有请求表单键,以找到 CALLBACKPARAM 值,以便过滤掉错误的回发,并在 GridviewPager Page_Load 事件中仅执行正确的回发。

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
}

关注点

我学会了如何扩展像 GridView 这样复杂的控制。

历史

如果您有任何建议,我很乐意听取。

© . All rights reserved.