Come Intercettare un controllo ASP.NET all'interno della riga di una GridView in Edit Mode

Giorgio Borelli

Evento RowUpdating di una GridView per intercettare un controllo ASP.NET all'interno della riga di una GridView in Edit Mode

Una delle esigenze molto sentite tra gli sviluppatori ASP.NET è quella di poter gestire ed avere il pieno controllo della GridView, un controllo molto usato per la presentazione, la paginazione e la modifica di liste di dati.

Tramite il controllo GridView di ASP.NET pertanto è facile gestire liste di dati, la GridView infatti presenta tutta una serie di proprietà che consentono con facilità di formattare, paginare e gestire le "liste". La GridView consente inoltre di gestire i dati sia in "Presentation Mode" che in "Edit Mode", quest'ultima modalità risulta comoda per l'aggiornamento (update) di un record rappresentato dalla singola riga della GridView, le cose si complicano un pò però quando si cerca di avere il controllo completo su un elemento asp.net all'interno della riga della GridView, in source view infatti non riusciamo ad accedere al controllo tramite il suo ID poichè non viene visto dalla classe Page in quanto "mascherato" all'interno della GridView stessa.

Come fare allora per accedere ai controlli specificati nelle righe di una GridView di asp.net in Edit Mode? Dobbiamo sfruttare l'Evento Row_Updating e scrivere qualche riga di codice per intercettare la riga selezionata e l'ID del controllo interessato, andiamo a scoprire come fare.

Supponiamo di avere una GridView per la gestione della lista dei nostri prodotti, con ID="GridViewProducts", per questa specifichiamo il DataSource dal quale preleviamo i dati e definiamo i TemplateFields (o altro tipo di colonna come ad es. BoundField) all'interno della proprieta Columns della GridView, uno per ogni colonna che desideriamo rappresentare. Tramite il TemplateField possiamo specificare i controlli voluti (siano questi asp.net o semplici tag html), inoltre possiamo anche dire alla nostra GridView cosa mostrarci a seconda se siamo in "Presentation Mode" o in "Edit Mode", distinguendo rispettivamente per il singolo TemplateField la definizione di un ItemTemplate e di un EditItemTemplate.

Bene, concentriamoci adesso sul nostro esempio, e supponiamo che al nostro prodotto sia associato un campo Image per consentire di associargli una immagine da visualizzare nella riga della griglia in presentation mode, mentre in edit mode specifichiamo un controllo "FileUpload" per consentire di selezionare una nuova immagine d'associare al prodotto. In questo caso il TemplateField specificato per la colonna immagine dei prodotti della GridViewProducts sarebbe pressapoco così:

<asp:TemplateField HeaderText="Immagine" ItemStyle-HorizontalAlign="Center">
    <ItemTemplate>
        <img src="../../HandlerImg.ashx?NameImg=<%# Eval("Image") %>&Size=48" />
    </ItemTemplate>
    <EditItemTemplate>
        <asp:FileUpload ID="FileUploadEditImage" ToolTip="Cambia l'immagine"
            runat="server" />
    </EditItemTemplate>
    <ItemStyle HorizontalAlign="Center"></ItemStyle>
</asp:TemplateField>

In questo modo quando siamo in presentation mode, tramite un semplice tag html img con il source src impostato su un'opportuno HttpHandler per la gestione delle immagini visualizziamo l'immagine del prodotto con un ridimensionamento in larghezza di 48px, mentre in edit mode specifichiamo un controllo asp.net FileUpload per poter consentire (se lo si vuole) di poter cambiare l'immagine associata al prodotto.

Per poter fare l'update del campo Image del nostro prodotto, dobbiamo però accedere per primo alla riga della GridView selezionata in Edit Mode e dopo al controllo FileUploadEditImage presente in essa, purtroppo questo non è possibile direttamente poichè non sappiamo a priori quale riga verrà selezionata nè tantomeno abbiamo il controllo diretto sul FileUpload in quanto generato all'interno di ogni singola riga della GridView.

Il controllo GridView di asp.net non consente infatti di estrarre ed aggiornare automaticamente i valori delle colonne specificati in controlli definiti all'interno di TemplateField (come invece avviene per i BounField), detti valori devono essere aggiunti automaticamente via codice attraverso la dictionary "NewValues".

Per ovviare a questa problematica dobbiamo agire allora via codice, sfruttando l'evento OnRowUpdating della GridView, tale evento viene richiamato proprio prima che vengano effettuati gli update dei campi specificati in Edit Mode nelle colonne della GridView, specifichiamo pertanto lo scatenarsi di tale evento nella GridView e la sua opportuna gestione via codice nel file .cs della pagina, così avremo, per la definizione degli eventi della GridView (file aspx):

OnRowUpdating="GridViewProducts_RowUpdating"

mentre nel source view (file .cs se scriviamo in C#) l'opportuno gestore dell'evento in C#:

protected void GridViewProducts_RowUpdating(object sender,GridViewUpdateEventArgs e)
    {
        ...

All'interno del gestore dell'evento RowUpdating per prima cosa dobbiamo intercettare quale delle righe della nostra GridView è stata selezionata per l'Edit Mode, per far ciò ricorriamo alla proprietà EditIndex della GridView, la quale ritorna un intero non negativo, indicante l'indice della riga selezionata, avendo l'indice tramite la proprietà Rows sempre della GridView, la quale ritorna una Collection delle righe generate, diventa facile creare un'istanza della classe GridViewRow, che altro non è che l'oggetto riga selezionato in Edit Mode della nostra GridViewProducts, il codice all'interno del nostro evento diventa pertanto:

// Controllo sull'indice
if (GridViewProducts.EditIndex >= 0)
{
    // Instance the selected row
    GridViewRow row = GridViewProducts.Rows[GridViewProducts.EditIndex];

A questo punto siamo a metà dell'opera, avendo la riga selezionata, adesso non ci resta che trovare il controllo interessato, nel nostro caso il FileUploadEditImage, tra quelli specificati nelle colonne della GridView, per realizzare ciò facciamo uso della potente funzione FindControl(string id) richiamabile dall'istanza della riga selezionata appena creata "row", la funzione FindControl vuole come parametro una stringa rappresentante il nome identificativo del controllo da cercare in molti controlli contenitori di asp.net che non è altro che il nome che abbiamo assegnato al controllo FileUpload, il codice pertanto è:

// Get the controls that contain the updated values
FileUpload FileUploadEditImage = (FileUpload)row.FindControl("FileUploadEditImage");

// controlliamo se il controllo FileUploadEditImage
// contiene un file da caricare
if (FileUploadEditImage != null && FileUploadEditImage.HasFile)
{
    //seguono le istruzioni per l'update del valore Image
    //...

Con queste righe di codice creiamo un'istanza proprio del controllo FileUpload interessato, importante fra l'altro è far notare come sia richiesto un cast esplicito del controllo cercato, poichè la funzione FindControl ritorna giustamente un Control generico non sapendo a priori quale può essere il controllo che cerchiamo, infine facciamo gli opportuni controlli sulla validità dell'istanza del FileUpload creato e se è stato specificato per esso un file da caricare, dopodichè seguono le istruzioni per l'update dei valori del campo.

NOTA: la funzione FindControl è richiamabile da tutti quei controlli asp.net che fungono da contenitori per altri controlli, quali Page, PlaceHolder, GridView o come nel nostro caso GridViewRow.

Ovviamente questa tecnica vale per qualsivoglia controllo noi vogliamo intercettare all'interno della riga selezionata, sia questo un FileUpload, una DropDownList, una CheckBox o una qualsiasi TextBox, basterà passare come parametro stringa l'id del nostro controllo da ricercare alla FindControl e specificare l'adeguato cast per il controllo che si vuole instanziare.

Per completezza infine riportiamo l'intero codice C# del gestore dell'evento OnRowUpdating dell'esempio sin qui illustrato, per l'aggiornamento di un record attraverso la selezione di una riga di una GridView in Edit Mode, mostrando anche come aggiornare il valore attraverso la dictionary "NewValues" dell'Event Args passato al gestore delll'evento, il codice è il seguente:

protected void GridViewProducts_RowUpdating(object sender,GridViewUpdateEventArgs e)
{
    // Get the GridViewRow object that represents the row being edite
    // from the Rows collection of the GridView control.
    if (GridViewProducts.EditIndex >= 0)
    {
        GridViewRow row = GridViewProducts.Rows[GridViewProducts.EditIndex];

        //Get the controls that contain the updated values
        FileUpload FileUploadEditImage = (FileUpload)row.FindControl("FileUploadEditImage");

        //controlliamo se il controllo FileUploadDocument
        //contiene un file da caricare
        if (FileUploadEditImage != null && FileUploadEditImage.HasFile)
        {
            e.NewValues["Image"] = FileUploadEditImage.FileName;
        }
}

Notare come avviene l'aggiornamento del campo "Image" nell'istruzione all'interno dell'ultimo if, attraverso la dictionary "NewValues" dove per indice specifichiamo proprio il nome del campo d'aggiornare.

Chiunque voglia aggiungere qualcosa o porre una domanda in merito all'argomento "Come Intercettare un controllo asp.net all'interno della riga di una GridView in Edit Mode", può farlo tramite i commenti, ogni vostro intervento sarà ben accetto.

Categorie: ASP.NET

Tags:

Pingbacks and trackbacks (1)+

Aggiungi Commento

biuquote
Loading