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