Stránkovací prvek Pagination pro formuláře ASP.NET – použití
V tomto článku navazuji na předchozí text, který byl věnován vnitřní architektuře prvku. Probereme detailně veřejné členy a připravíme ukázku použití pro stránkování, kdy známe celkový počet záznamů, ale také pro případ, kdy celkový počet neznáme nebo je jeho zjištění komplikované a náročné.
Jak jsme si popsali v předchozím článku, prvek Pagination zajišťuje inteligentní vykreslení daného počtu čísel stránek a automaticky doplní odkaz na „další sadu stránek“. Prvky, které nemají v dané situaci smysl, jsou zakázané (například přechod na předchozí stránku v situaci, kdy jsme na první stránce). Je možné volit z režimu zobrazení tlačítek vpřed a zpět nebo číselných radibuttonů nebo zobrazit obojí (viz ukázky vzhledu).
K dispozici je vám kompletní zdrojový kód tohoto prvku ke stažení a otestování.
Veřejní členové – implementace
Nejdříve si ukážeme jejich implementaci – v podstatě na ní není nic převratného, proto jsem v kódu ponechal také interní anglické komentáře a níže jsem připravil pouze přehledný seznam členů s českým komentářem.
/// <summary>
/// Go button text
/// </summary>
public String GoToPageText
{
get
{
return btnGo.Text;
}
set
{
btnGo.Text = value;
}
}
/// <summary>
/// Go button tooltip
/// </summary>
public String GoToPageToolTip
{
get
{
return btnGo.ToolTip;
}
set
{
btnGo.ToolTip = value;
}
}
/// <summary>
/// Numeric pages tooltip
/// </summary>
public String NumericPagesToolTip
{
get
{
return rblNumeric.ToolTip;
}
set
{
rblNumeric.ToolTip = value;
}
}
/// <summary>
/// Next page button text
/// </summary>
public String NextPageText
{
get
{
return btnNext.Text;
}
set
{
btnNext.Text = value;
}
}
/// <summary>
/// Next page button tooltip
/// </summary>
public String NextPageToolTip
{
get
{
return btnNext.ToolTip;
}
set
{
btnNext.ToolTip = value;
}
}
/// <summary>
/// Previous page button text
/// </summary>
public String PrevPageText
{
get
{
return btnPrev.Text;
}
set
{
btnPrev.Text = value;
}
}
/// <summary>
/// Previous page button tooltip
/// </summary>
public String PrevPageToolTip
{
get
{
return btnPrev.ToolTip;
}
set
{
btnPrev.ToolTip = value;
}
}
/// <summary>
/// Button CSS class
/// </summary>
public String ButtonCssClass
{
get
{
return lblNextPrev.CssClass;
}
set
{
lblNextPrev.CssClass = lblGo.CssClass = value;
}
}
/// <summary>
/// RadioButton CSS class
/// </summary>
public String RadioButtonCssClass
{
get
{
return rblNumeric.CssClass;
}
set
{
rblNumeric.CssClass = value;
}
}
/// <summary>
/// Gets or sets the virtual number of items in the Pagination control.
/// </summary>
public Int32 VirtualItemCount
{
get
{
object o = this.ViewState[„VirtualItemCount“];
if (o != null)
return (Int32) o;
else
return _virtualItemCount;
}
set
{
this.ViewState[„VirtualItemCount“] = value;
virtualItemCount = value;
}
}
/// <summary>
/// Gets or sets the index of the currently displayed page.
/// </summary>
public Int32 SelectedPageIndex
{
get
{
object o = this.ViewState[„SelectedPageIndex“];
if (o != null)
return (Int32) o;
else
return _selectedPageIndex;
}
set
{
this.ViewState[„SelectedPageIndex“] = value;
selectedPageIndex = value;
}
}
/// <summary>
/// Gets total number of pages to pagination.
/// </summary>
public Int32 PageCount
{
get
{
_calculatePageCount();
return _pageCount;
}
}
/// <summary>
/// Gets or sets the number of items to display on a single page of the paginated control.
/// </summary>
public Int32 PageSize
{
get
{
object o = this.ViewState[„PageSize“];
if (o != null)
return (Int32) o;
else
return _pageSize;
}
set
{
this.ViewState[„PageSize“] = value;
_pageSize = value;
}
}
/// <summary>
/// Gets or sets the number of numeric buttons to display concurrently
/// </summary>
public Int32 PageButtonCount
{
get
{
object o = this.ViewState[„PageButtonCount“];
if (o != null)
return (Int32) o;
else
return _pageButtonCount;
}
set
{
this.ViewState[„PageButtonCount“] = value;
_pageButtonCount = value;
}
}
/// <summary>
/// Gets or sets the direction that the radio buttons within the group are displayed.
/// </summary>
public PaginationNumericRepeatDirection NumericRepeatDirection
{
get { return _numericRepeatDirection; }
set { _numericRepeatDirection = value; }
}
/// <summary>
/// Gets or sets a value that specifies whether the pager element displays buttons that link to the next and previous page, or numeric radio buttons.
/// </summary>
public PaginationMode Mode
{
get { return _mode; }
set { _mode = value; }
}
/// <summary>
/// Gets or sets a value indicating whether validation is performed when the control is clicked.
/// </summary>
public Boolean CausesValidation
{
get
{
return btnPrev.CausesValidation;
}
set
{
btnPrev.CausesValidation = btnNext.CausesValidation = btnGo.CausesValidation = rblNumeric.CausesValidation = value;
}
}
U některých vlastností vidíme, jak je jejich hodnota udržována prostřednictvím ViewState, což je samozřejmě důležité – aby vlastnosti stránkovacího prvku přežily PostBack.
Veřejní členové – přehledný popis
Vlastnosti
public String GoToPageText– text tlačítka pro přechod na zvolenou stránku, tlačítko se zobrazuje pouze pokud klient nepodporuje JavaScriptpublic String GoToPageToolTip– tooltip tlačítka pro přechod na zvolenou stránku, tlačítko se zobrazuje pouze pokud klient nepodporuje JavaScriptpublic String NumericPagesToolTip– tooltip radiobuttonů pro přechod na zvolenou stránkupublic String NextPageText– text tlačítka pro přechod na následující stránkupublic String NextPageToolTip– tooltip tlačítka pro přechod na následující stránkupublic String PrevPageText– text tlačítka pro přechod na předchozí stránkupublic String PrevPageToolTip– text tlačítka pro přechod na následující stránkupublic String ButtonCssClass– třída CSS pro tlačítkapublic String RadioButtonCssClass– třída CSS pro radiobuttonypublic Int32 VirtualItemCount– vrací nebo nastaví virtuální (celkový) počet položek, které jsou stránkovány – vlastnost má týž význam, jako u prvků DataGrid nebo GridViewpublic Int32 SelectedPageIndex– vrací nebo nastaví index právě zvolené stránkypublic Int32 PageCount– pouze vrací celkový počet stránek ke stránkovánípublic Int32 PageSize– vrací nebo nastaví počet položek v jedné stránce – vlastnost má týž význam, jako u prvků DataGrid nebo GridViewpublic Int32 PageButtonCount– vrací nebo nastaví maximální počet položek číselných buttonů (čísel) stránek, na konci nebo začátku seznamu je generován odkaz pro přechod na „další sadu“ stránek, pokud nějaká předchází či následuje – vlastnost má týž význam, jako u prvků DataGrid nebo GridViewpublic PaginationNumericRepeatDirection NumericRepeatDirection– styl zobrazení čísel stránek – radiobuttonůpublic PaginationMode Mode– režim zobrazení stránkovacích prvkůpublic Boolean CausesValidation– nastavuje, zda použití prvku vyvolává validaci stránky
Události
public event EventHandler SelectedPageIndexChanged– je vyvolána v okamžiku, kdy je změněn index zvolené stránky, hodí se tedy pro získání dat dané stránky z datového zdroje a navázání na zobrazovací prvek
Enumerace
public enum PaginationMode– režim zobrazení ovládacích prvků- AllControls (čísla stránek i tlačítka vpřed a zpět)
- NextPrev (pouze tlačítka vpřed a zpět)
- Numeric (pouze čísla stránek)
public enum PaginationNumericRepeatDirection– způsob zobrazení čísel stránek- Horizontal (vodorovně)
- Vertical (svisle)
Příklad použití pro SqlDataReader k naplnění Repeateru s využitím stránkovací procedury
Tento prvek se výborně hodí pro použití ve spojení s univerzální stránkovací procedurou.
private void Page_Load(object sender, System.EventArgs e)
{
// nastavit lokalizované texty a tooltipy stránkovacího prvku
pgnSearch.GoToPageText = LocalizationManager.GetString(„PaginationGoToPageText“);
pgnSearch.GoToPageToolTip = LocalizationManager.GetString(„PaginationGoToPageToolTip“);
pgnSearch.NumericPagesToolTip = LocalizationManager.GetString(„PaginationNumericPagesToolTip“);
pgnSearch.NextPageText = LocalizationManager.GetString(„PaginationNextPageText“);
pgnSearch.NextPageToolTip = LocalizationManager.GetString(„PaginationNextPageToolTip“);
pgnSearch.PrevPageText = LocalizationManager.GetString(„PaginationPrevPageText“);
pgnSearch.PrevPageToolTip = LocalizationManager.GetString(„PaginationPrevPageToolTip“);
..
if (!Page.IsPostBack)
Bind_Page(sender, e); }
private void Bind_Page(Object sender, EventArgs e)
{
using (SqlConnection connection = new SqlConnection(PublicDBReaderString))
{
using (SqlCommand myCmd = new SqlCommand(„[dbo].[PaginateTable]“,connection))
{
myCmd.CommandType = CommandType.StoredProcedure;
myCmd.Parameters.Add(„@PageSize“, SqlDbType.Int).Value = pgnSearch.PageSize;
myCmd.Parameters.Add(„@CurrentPageIndex“, SqlDbType.Int).Value = pgnSearch.SelectedPageIndex;
myCmd.Parameters.Add(„@TableName“, SqlDbType.VarChar,64).Value = „[dbo].[Events]“;
myCmd.Parameters.Add(„@KeyField“, SqlDbType.VarChar,32).Value = „[EventDate]“;
myCmd.Parameters.Add(„@RowFilter“, SqlDbType.VarChar,3128).Value = „DATEDIFF(dd,[EventDate],GETDATE()) <= 0“;
try
{
connection.Open();
using (SqlDataReader myReader = myCmd.ExecuteReader(CommandBehavior.CloseConnection))
{
if (myReader.Read())
pgnSearch.VirtualItemCount = myReader.GetInt32(0);
else
pgnSearch.VirtualItemCount = 0;
if (pgnSearch.PageCount > 1)
pgnSearch.Visible = true;
else
pgnSearch.Visible = false;
myReader.NextResult();
rptSearch.DataSource = myReader;
rptSearch.DataBind();
}
}
catch
{
lblError.Visible = true;
}
}
}
}
private void InitializeComponent()
{ // zaregistrovat obsluhy událostí
this.pgnSearch.SelectedPageIndexChanged += new System.EventHandler(this.Bind_Page);
this.Load += new System.EventHandler(this.Page_Load);
}
V této ukázce principu řešení vidíme naplnění Repeateru zdrojem dat a také nastavení hodnot stránkovacího prvku – tak, aby byl v souladu počet skutečně vrácených záznamů ze zdroje pro danou stránku a vlastnosti stránkovacího prvku. Vidíme také zaregistrovanou obsluhu události při změně indexu stránky – voláme jedinou metodu, načtení správných řádků pro danou stránku je v ní zajištěno právě využitím vlastností stránkovacího prvku, který údaje o zvolené stránce i o počtu řádků pro stránku sám udržuje.
Příklad použití v designu stránky
<div class=“pagingElement“>
<Pc:Pagination Id=“pgnSearch“ Mode=“AllControls“ Visible=“False“ CausesValidation=“False“ ButtonCssClass=“pageButton“ RadioButtonCssClass=“pageRadio“ PageButtonCount=“5″ PageSize=“10″ RunAt=“server“ />
</div>
V ukázce vidíme nastavení režimu na číslované stránky i tlačítka vpřed a zpět, je nastavena třída stylu pro tlačítka i radiobuttony, počet čísel stránek je nastaven na maximálně 5 a počet řádků na stránce na 10.
Stránkování, kdy neznáme celkový počet záznamů
Takové stránkování je zdánlivě neřešitelné, ovšem jedna možnost zde je. Musíme splnit dvě podmínky – jednak musíme vypnout volbu číslovaných stránek a jednak nám zdroj dat musí poskytnout údaj o tom, zda za právě vrácenými záznamy je možné očekávat ještě alespoň jeden následující (je možný přechod na další stránku). Když toto splníme, řešení může vypadat takto:
if (Results.HasNext)
pgnSearch.VirtualItemCount = 2000;
else
{
if (Results.Length == pgnSearch.PageSize)
pgnSearch.VirtualItemCount = pgnSearch.SelectedPageIndex*pgnSearch.PageSize;
else
pgnSearch.VirtualItemCount = (pgnSearch.SelectedPageIndex*pgnSearch.PageSize)-pgnSearch.PageSize + Results.Length;
}
Vlastnost Results.HasNext ukazuje, zda jsou k dispozici ještě nějaké další záznamy – pokud ano, jednoduše nastavíme celkový počet stránek na nějakou přiměřeně vysokou hodnotu. Pokud ne, pak vyhodnotíme, jestli je aktuální stránka zaplněná až do konce, a podle toho potom nastavíme celkový počet záznamů ve vlastnosti VirtualItemCount tak, aby odpovídal skutečnému počtu zobrazitelných záznamů – prvek potom sám rozhodne, zda povolit či zakázat tlačítko pro přechod na další stránku.
Použití v designu bez celkového množství záznamů
<div class=“pagingElement“>
<Pc:Pagination Id=“pgnSearch“ Mode=“NextPrev“ Visible=“False“ CausesValidation=“False“ ButtonCssClass=“pageButton“ PageSize=“10″ RunAt=“server“ />
</div>
V ukázce vidíme nastavení režimu pouze na tlačítka vpřed a zpět, je nastavena třída stylu pro tlačítka a počet řádků na stránce na 10.
Zbývá dodat, že chystané Visual Studio „Orcas“ přichází s novým stránkovacím prvkem DataPager – ten je ovšem závislý na klientském skriptování a tak v případech, kde tuto závislost nechceme, bude mít dále své místo i tento prvek.







