Sunday, February 8, 2009

PagerTemplate per GridView

. Sunday, February 8, 2009

Molto spesso mi capita di vedere griglie che mostrano l’intero set di dati senza fornire un accesso tramite paginazione. Personalmente credo che offrire solo un sottinsieme di record sia fondamentale.
Premetto che l'’intento di questo post non è quello di parlarvi della paginazione, dei benefici che questa può portare all’applicazione, nè tantomeno realizzare un custom paging.
A tal riguardo trovate moltissimo materiale in rete, giusto per citare qualche fonte:
ASP.NET Custom Paging with GridView using ObjectDataSource
GridView Paging using ASP.NET AJAX Slider Extender

Quello che invece cercherò di illustrare è come sia possibile personalizzare il paging del controllo GridView utilizzando il property PagerTemplate.
Ma partiamo con ordine, descrivendo a grandi linee l’idea: unire un paging a una scrollbar. Tramite i due classici pulsanti next e prev sarà possibile spostare la scrollbar del paginatore, permettendo all’utente di aumentarne la velocità di spostamento restando semplicemente con il cursore del mouse sui relativi pulsanti:
Paging2
Il tutorial presenta in parti uguali codice Asp.Net e JavaScript.
Partiamo dal markup del controllo GridView:

   1: <table cellpadding="0" cellspacing="0" border="0">
   2:   <tr>
   3:     <td><img src="img/ang_top_sn.jpg" /></td>
   4:     <td background="img/top.jpg"></td>
   5:     <td><img src="img/ang_top_dx.jpg" /></td>
   6:   </tr>
   7:   <tr>
   8:     <td background="img/fondo_sn.jpg"></td>
   9:     <td>
  10:       <asp:GridView ID="dgrTest" runat="server" AllowPaging="true" PageSize="5" Width="750px">
  11:         <RowStyle BackColor="#999999" />
  12:           <PagerTemplate>
  13:             <table width="100px" align="center">
  14:               <tr>
  15:                 <td width="24" align="left">
  16:                   <img id="prev" src="img/minus.jpg" width="24" height="24" onmouseover="fnPrev()" 
onmouseout="stop()" />
  17:                 </td>
  18:                 <td>
  19:                   <div id="divScroll" 
style="width: 200px; height: 40px; overflow-x: hidden; overflow-y: hidden">
  20:                     <asp:Table ID="tbItems" runat="server"></asp:Table>
  21:                   </div>
  22:                 </td>
  23:                 <td width="24" align="right">
  24:                   <img id="next" src="img/plus.jpg" width="24" height="24" onmouseover="fnNext()" 
onmouseout="stop()" />
  25:                 </td>
  26:               </tr>
  27:             </table>
  28:           </PagerTemplate>
  29:         <AlternatingRowStyle BackColor="#CCCCCC" />
  30:       </asp:GridView>
  31:     </td>
  32:     <td background="img/fondo_dx.jpg"></td>
  33:   </tr>
  34:   <tr>
  35:     <td><img src="img/ang_bott_sn.jpg" /></td>
  36:     <td background="img/bott.jpg"></td>
  37:     <td><img src="img/ang_bott_dx.jpg" /></td>
  38:   </tr>
  39: </table>


Questo markup produce il seguente risultato:Paging1

Nel PagerTemplate sono presenti principalmente quattro elementi.
Un div che tramite la proprietà overflow ci consente di gestire il suo contenuto al superamento dei limiti imposti dai valori assegnati alle proprietà width e/o height.

La tabella tblItems targata runat server contenente i numeri di pagina.
Infine alle due estremità del div sono presenti due immagini (con segno più e con segno meno) che consentono lo spostamento della scrollbar in entrambi i sensi.

Il codice lato server per popolare la tabella con id tblItems è abbastanza semplice. Consiste nel creare un numero di celle, pari al numero totale di pagine. In ogni cella viene aggiunto a runtime un controllo LinkButton:


   1: private void CreatePager()
   2: {
   3:   Table tbItems = (Table)dgrTest.BottomPagerRow.Cells[0].FindControl("tbItems");
   4:   if (tbItems != null)
   5:   {
   6:     TableRow row = new TableRow();
   7:     TableCell cell;
   8:     for (int cntPage = 1; cntPage <= dgrTest.PageCount; cntPage++)
   9:     {
  10:       LinkButton lnkItem = new LinkButton();
  11:       lnkItem.ID = "page" + cntPage.ToString();
  12:       lnkItem.Click += new EventHandler(lnkItem_Click);
  13:       lnkItem.Text = cntPage.ToString();
  14:       //Elemento corrente
  15:       if (dgrTest.PageIndex + 1 == cntPage)
  16:         //Layout link selezionato
  17:         lnkItem.BackColor = System.Drawing.Color.Yellow;
  18:       cell = new TableCell();
  19:       cell.Style.Add(HtmlTextWriterStyle.TextAlign, "center");
  20:       cell.Controls.Add(lnkItem);
  21:       row.Cells.Add(cell);
  22:     }
  23:     tbItems.Rows.Add(row);
  24:     tbItems.Width = Unit.Pixel(row.Cells.Count * 30);
  25:   }
  26: }


Sull’evento click dei LinkButton (necessario per spostarci di pagina):
   1: void lnkItem_Click(object sender, EventArgs e)
   2: {
   3:   dgrTest.PageIndex = Convert.ToInt32(((LinkButton)sender).Text) - 1;
   4:   //Rieseguire il Bind
   5:   CreatePager();
   6: }

Ma vediamo come il codice JavaScript si integra con quanto visto fin'ora.
Per comodità e per un rapido sviluppo userò il Framework JQuery.

Partiamo dall'implementazione dei due eventi: omouseover e onmouseout presenti sulle immagini next e prev.
Sull'omouseover dell'immagine con id next viene richiamata la funzione fnNext. Quest'ultima a sua volta, richiama il metodo: setInterval(), che permette di creare intervalli prestabiliti nell'arco di una routine:

   1:  
   2: function fnNext() {
   3:   scrollTimer = setInterval(speedNext, 10);
   4: }

Il primo argomento del metodo rappresenta la funzione da eseguire, mentre il secondo sono i millisecondi di attesa. La variabile globale scrollTimer è importante perchè ci consente di interrompere l'esecuzione della funzione richiamando il metodo clearInterval.
Quest'ultimo viene innescato allo scatenarsi dell'evento onmouseover:

   1: function stop() {
   2:   clearInterval(scrollTimer);
   3:   speed = 5;
   4: }
La logica di spostamento è concentrata nelle due funzioni speedNext e speedPrev.
Iniziamo dalla funzione speedNext:
   1: var scrollTimer;
   2: var speed = 5;
   3: function speedNext() {
   4:   if ($('#divScroll').scrollLeft() != ($('#divScroll table[id$=tbItems]').width() - $('#divScroll').width())) {
   5:     document.getElementById("divScroll").scrollLeft += speed;
   6:     speed += 1;
   7:     $('#valueScrollLeft').val($('#divScroll').scrollLeft());
   8:   }
   9: }

Tramite la prima istruzione (riga numero 4) posso verificare se la barra di scorrimento ha raggiunto il limite massimo.

E’ stato necessario assegnare una dimensione fissa alla tabella contenente i numeri di pagina (vedere riga numero 24 del codice lato server).
Supponendo che la tabella contenuta nel div abbia una larghezza di 200 px e che il div sia invece di 100 px, il valore massimo che potrà essere assegnato alla proprietà scrollLeft risulterà uguale a 200px - 100px = 100px.
Nella seconda istruzione (riga numero 5) compare un'altra variabile globale: speed.
Questa inizialmente valorizzata a 5, viene di volta in volta incrementata di 1 (vedere istruzione riga 6). Indica la posizione corrente della scrollbar (vedere istruzione riga 5).
Invece l’immagine con id prev, tramite la funzione speedPrev, implementa un comportamento opposto a quello appena descritto:

   1: function speedPrev() {
   2:   if ($('#divScroll').scrollLeft() != 0) {
   3:     document.getElementById("divScroll").scrollLeft -= speed;
   4:     speed += 1;
   5:     $('#valueScrollLeft').val($('#divScroll').scrollLeft());
   6:   }
   7: }

La posizione iniziale è uguale a 0 (riga 2), ed inoltre il valore assegnato alla proprietà scrollLeft invece di essere incrementato viene decrementato (riga 3). 
Infine per evitare che ad ogni postback si perda la posizione della scrollbar, il valore della proprietà scrollLeft viene memorizzato in un campo hidden. Così facendo posso settare correttamente la proprietà (il controllo avviene ad caricamento della pagina):

   1: $(document).ready(function() {
   2:   if ($('#valueScrollLeft').val() != "")
   3:     $('#divScroll').scrollLeft($('#valueScrollLeft').val());
   4: });

Markup del campo hidden:
   1: <asp:HiddenField ID="valueScrollLeft" runat="server" />

Concludo dicendo che come al solito questo mio post non vuole essere un punto di arrivo ma bensì di partenza.
Buono studio ;)

0 commenti:

Post a Comment