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 JavaScript
  • public String GoToPageToolTip – tooltip tlačítka pro přechod na zvolenou stránku, tlačítko se zobrazuje pouze pokud klient nepodporuje JavaScript
  • public String NumericPagesToolTip – tooltip radiobuttonů pro přechod na zvolenou stránku
  • public String NextPageText – text tlačítka pro přechod na následující stránku
  • public String NextPageToolTip – tooltip tlačítka pro přechod na následující stránku
  • public String PrevPageText – text tlačítka pro přechod na předchozí stránku
  • public String PrevPageToolTip – text tlačítka pro přechod na následující stránku
  • public String ButtonCssClass – třída CSS pro tlačítka
  • public String RadioButtonCssClass – třída CSS pro radiobuttony
  • public 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 GridView
  • public Int32 SelectedPageIndex – vrací nebo nastaví index právě zvolené stránky
  • public 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 GridView
  • public 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 GridView
  • public 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.

Žádný příspěvek v diskuzi

Odpovědět