kejames 學習筆記本

這裡是Kejames的筆記本,歡迎各位網友給予指教,謝謝。
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

[轉載]GridView with custom Digg-like paging

Posted on 2007-09-26 09:23  Kejames  阅读(465)  评论(0)    收藏  举报

GridView is a great highly customizable ASP.NET control. Today I want to show, how to create derived control, which allows to add Digg-style pagination to your application.

 

First, we will create derived control and add property UseCustomPager, which will define whether or not to use Digg-style pagination:

using System;
using System.Globalization;
using System.Reflection;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;

namespace App_Code
{
    
public class GridViewWithPager : GridView
    
{
        
public bool UseCustomPager
        
{
            
get return (bool?) ViewState["UseCustomPager"?? false; }
            
set { ViewState["UseCustomPager"= value; }
        }

    }

}

GridView has virtual method InitializePager which could be overridden to create our custom pager:

protected override void InitializePager(GridViewRow row, int columnSpan, PagedDataSource pagedDataSource)
{
    
if (UseCustomPager)
        CreateCustomPager(row, columnSpan, pagedDataSource);
    
else
        
base.InitializePager(row, columnSpan, pagedDataSource);
}

Now let’s create our custom pager:

protected virtual void CreateCustomPager(GridViewRow row, int columnSpan, PagedDataSource pagedDataSource)
{
    
int pageCount = pagedDataSource.PageCount;
    
int pageIndex = pagedDataSource.CurrentPageIndex + 1;
    
int pageButtonCount = PagerSettings.PageButtonCount;

    TableCell cell 
= new TableCell();
    row.Cells.Add(cell);
    
if (columnSpan > 1) cell.ColumnSpan = columnSpan;

    
if (pageCount > 1)
    
{
        HtmlGenericControl pager 
= new HtmlGenericControl("div");
        pager.Attributes[
"class"= "pagination";
        cell.Controls.Add(pager);

        
int min = pageIndex - pageButtonCount;
        
int max = pageIndex + pageButtonCount;

        
if (max > pageCount)
            min 
-= max - pageCount;
        
else if (min < 1)
            max 
+= 1 - min;

        
// Create "previous" button
        Control page = pageIndex > 1
                        
? BuildLinkButton(pageIndex - 2, PagerSettings.PreviousPageText, "Page""Prev")
                        : BuildSpan(PagerSettings.PreviousPageText, 
"disabled");
        pager.Controls.Add(page);

        
// Create page buttons
        bool needDiv = false;
        
for (int i = 1; i <= pageCount; i++)
        
{
            
if (i <= 2 || i > pageCount - 2 || (min <= i && i <= max))
            
{
                
string text = i.ToString(NumberFormatInfo.InvariantInfo);
                page 
= i == pageIndex
                        
? BuildSpan(text, "current")
                        : BuildLinkButton(i 
- 1, text, "Page", text);
                pager.Controls.Add(page);
                needDiv 
= true;
            }

            
else if (needDiv)
            
{
                page 
= BuildSpan("&hellip;"null);
                pager.Controls.Add(page);
                needDiv 
= false;
            }

        }


        
// Create "next" button
        page = pageIndex < pageCount
                
? BuildLinkButton(pageIndex, PagerSettings.NextPageText, "Page""Next")
                : BuildSpan(PagerSettings.NextPageText, 
"disabled");
        pager.Controls.Add(page);
    }

}


private Control BuildLinkButton(int pageIndex, string text, string commandName, string commandArgument)
{
    PagerLinkButton link 
= new PagerLinkButton(this);
    link.Text 
= text;
    link.EnableCallback(ParentBuildCallbackArgument(pageIndex));
    link.CommandName 
= commandName;
    link.CommandArgument 
= commandArgument;
    
return link;
}


private Control BuildSpan(string text, string cssClass)
{
    HtmlGenericControl span 
= new HtmlGenericControl("span");
    
if (!String.IsNullOrEmpty(cssClass)) span.Attributes["class"= cssClass;
    span.InnerHtml 
= text;
    
return span;
}

Several pager settings used in this code:

  • PagerSettings.PreviousPageText — text to be shown on the “Previous” button.
  • PagerSettings.NextPageText — text to be shown on the “Next” button.
  • PagerSettings.PageButtonCount — how many pages to show before and after the current page.

You could see, that in BuildLinkButton method I have used custom control PagerLinkButton. This is just descendant of the LinkButton control which simplifies usage inside our GridViewWithPager:

using System;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace App_Code
{
    
public class PagerLinkButton : LinkButton
    
{
        
public PagerLinkButton(IPostBackContainer container)
        
{
            _container 
= container;
        }


        
public void EnableCallback(string argument)
        
{
            _enableCallback 
= true;
            _callbackArgument 
= argument;
        }


        
public override bool CausesValidation
        
{
            
get return false; }
            
set throw new ApplicationException("Cannot set validation on pager buttons"); }
        }


        
protected override void Render(HtmlTextWriter writer)
        
{
            SetCallbackProperties();
            
base.Render(writer);
        }


        
private void SetCallbackProperties()
        
{
            
if (_enableCallback)
            
{
                ICallbackContainer container 
= _container as ICallbackContainer;
                
if (container != null)
                
{
                    
string callbackScript = container.GetCallbackScript(this, _callbackArgument);
                    
if (!string.IsNullOrEmpty(callbackScript)) OnClientClick = callbackScript;
                }

            }

        }


        
Private fields
    }

}

Our control is almost done. All we need is to define method ParentBuildCallbackArgument. As you could see from GridView sources, this method is used for serializing page index, sort direction and sort expression, but for some reason, it has been defined as internal. I don’t like hacks, but in this case I think that I can cheat a little:

private string ParentBuildCallbackArgument(int pageIndex)
{
    MethodInfo m 
=
        
typeof (GridView).GetMethod("BuildCallbackArgument", BindingFlags.NonPublic | BindingFlags.Instance, null,
                                    
new Type[] {typeof (int)}null);
    
return (string) m.Invoke(thisnew object[] {pageIndex});
}

BTW, as you could see, I have not added any comments to methods. It is done specially, because I don’t want to create custom controls library, just sharing my experience :-)

And now I’ll show you example of usage:

<asp:XmlDataSource runat="server" ID="xdsCountries" 
    DataFile
="~/App_Data/CountryCodeList.xml" />

<ac:GridViewWithPager runat="server" UseCustomPager="true" AllowPaging="true"
    DataSourceID
="xdsCountries" PageSize="10" AutoGenerateColumns="false">
    
<PagerSettings PreviousPageText="&laquo; previous"
        NextPageText
="next &raquo;" PageButtonCount="3" />
    
<Columns>
        
<asp:TemplateField HeaderText="Code">
            
<ItemTemplate><%# XPath("CountryCoded"%></ItemTemplate>
        
</asp:TemplateField>
        
<asp:TemplateField HeaderText="Name">
            
<ItemTemplate><%# XPath("CountryName"%></ItemTemplate>
        
</asp:TemplateField>
    
</Columns>
</ac:GridViewWithPager>


Full source code could be downloaded here.Digg-Style Pagination

http://www.strangerstudios.com/sandbox/pagination/diggstyle.php

---
Fom:http://kpumuk.info/asp-net/gridview-with-custom-digg-like-pager/