Mi è capitato di avere la necessità di creare all'interno di una colonna di gridview del codice javascript il quale potesse in qualche modo ottenere alcuni dei dati in corso di visualizzazione nella gridview stessa. Ad esempio, in riferimento alle popup di tipo subModal, di cui vi ho parlato in precedenza mi è stato necessario comporre dinamicamente l'url da passare alla chiamata Javascript che ne causa la comparsa.

La gridview, a meno che non abbia preso un abbaglio, non dispone di una campo che permetta la formattazione di codice lato client, a meno che non si voglia utilizzare un TemplateField. Inutile anche tentae di introdurre il prefisso "javascript:" l'url formattato infatti il runtime di ASP.NET per questioni di sicurezza lo sopprime senza colpo ferire. Ho perciò deciso di indagare un po' sul funzionamento della gridview per capire se era possibile estendere l'HyperLinkField in modo da gestire anche la formattazione di un ClientLink al pari di quello che si può fare con il NavigateUrl. Ecco il codice che ne ho tirato fuori:

using System;
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 System.Collections.Generic;
using System.ComponentModel;

namespace Elite.Web.DataSources
{
    
/// <summary>
    /// 
Classe che implementa AdvHyperLinkField
    
/// </summary>
    
public class AdvHyperLinkField : HyperLinkField
    {
        
/// <summary>
        /// 
ctor
        
/// </summary>
        
public AdvHyperLinkField()
        { }

        
/// <summary>
        /// 
Inizializza una cella della GridView
        
/// </summary>
        /// <param name="cell">
cella</param>
        /// <param name="cellType">
tipo di cella</param>
        /// <param name="rowState">
stato della riga</param>
        /// <param name="rowIndex">
indica della riga</param>
        
public override void InitializeCell(
            DataControlFieldCell cell,
            DataControlCellType cellType,
            DataControlRowState rowState,
            
int rowIndex)
        {
            
// dapprima chiama il metodo base
            
base.InitializeCell(cell, cellType, rowState, rowIndex);

            
// se si tratta di una DataCell
            
if (cellType == DataControlCellType.DataCell &&
                cell.Controls.Count > 0)
            {
                
// trova l'hyperlink
                
HyperLink link = cell.Controls[0] as HyperLink;

                
// e aggancia l'evento DataBinding
                
if (link != null)
                    link.DataBinding += 
new EventHandler(link_DataBinding);
            }
        }

        
/// <summary>
        /// 
Gesisce l'evento che viene sollevato durante il DataBinding
        
/// </summary>
        /// <param name="sender">
il link che ha generato l'evento</param>
        /// <param name="e">
i dati dell'evento</param>
        
void link_DataBinding(object sender, EventArgs e)
        {
            
// trova il link che ha generato l'evento
            
HyperLink link = sender as HyperLink;
            
// preleva il controllo container
            
Control container = link.NamingContainer;

            
if (container != null)
            {
                
bool found;

                
// trova il DataItem corrente nel Container
                
object dataItem = DataBinder.GetDataItem(container, out found);

                
if (found)
                {
                    
// se lo ha trovato crea una list con le traduzioni
                    
List<string> paramList = new List<string>();

                    
// traduce ogni campo richiesto nel dato corrispondente
                    
foreach (string name in this.DataNavigateUrlFields)
                        paramList.Add(
                            DataBinder.GetPropertyValue(
                                dataItem, 
                                name) 
as string);

                    
// formatta l'url clent
                    
link.Attributes["onclick"] = 
                        
string.Format(
                            
this.DataClientNavigateUrlFormatString, 
                            paramList.ToArray());

                    
// assegna un url fittizio se non è giù stato 
                    // assegnato (altrimenti l'hypelink non appare)
                    
if (!string.IsNullOrEmpty(link.NavigateUrl))
                        link.NavigateUrl = "~/";
                }
            }
        }

        
/// <summary>
        /// 
proprietà contente i campi da utilizzare nella formattazione
        
/// </summary>
        
public string[] DataClientNavigateUrlFields
        {
            
get
            
{
                
if (ViewState["DataNavigateUrlFields"] == null)
                    ViewState["DataNavigateUrlFields"] = 
new string[0];

                
return (string[])ViewState["DataNavigateUrlFields"];
            }
            
set { ViewState["DataNavigateUrlFields"] = value; }
        }

        
// stringa da formattare
        
public string DataClientNavigateUrlFormatString
        {
            
get
            
{
                
if (ViewState["DataClientNavigateUrlFormatString"] == null)
                    ViewState["DataClientNavigateUrlFormatString"] = 
string.Empty;

                
return (string)ViewState["DataClientNavigateUrlFormatString"];
            }
            
set { ViewState["DataClientNavigateUrlFormatString"] = value; }
        }
    }
}

 

Questo nuovo tipo di campo, derivato direttamente da HyperLinkField, aggiunge due proprietà che consentono di decidere come formattare il codice eseguito in corrispondenza dell'evento javascript "onClick". DataClientNavigateUrlFields e DataClientNavigateUrlFormatString si comportano esattamente come le proprietà esposte da HyperLinkField e dedicate all'url. Vediamo un attimo di sottolinearne il funzionamento: La classe fa innanzitutto l'override del metodo InitializeCell. Questo metodo viene chiamato in corrispondenza di ogni cella della gridview e consente di aggiungere elementi al contenuto. Nel nostro caso dapprima viene richiamato il metodo base che si occupa di creare l'HyperLink nella cella, in seguito nel viene cercato tale link e ad esso si aggancia l'evento DataBinding solo nel caso di celle di tipo DataCell (escludendo quindi header e footer). In questo modo, ad ogni evento di bind dell'HyperLink di ogni cella verrà chiamato il metodo link_DataBinding() che estrae il DataItem dal contesto della GridView ed effettua il binding delle due nuove proprietà.

Nello stesso metodo c'è anche un piccolo stratagemma da evidenziare. Qualora il campo NavigareUrl sia vuoto, si inserisce un url fittizio (~/) sempre valido, in modo da provocare la comparsa dell'hyperlink che in caso contrario non verrebbe mostrato.

powered by IMHO 1.3


per leggere il post originale o inviare un commento visita il seguente indirizzo: ASP.NET: AdvancedHyperLinkField