Asp.Net Creazione di un gridview con un pannello di espansione

Articolo che illustra in Asp.net 4, come aggiungere alle righe di un controllo GridView un pannello che integra i dati.

il
Sviluppatore Microsoft .Net, Collaboratore di IProgrammatori

Introduzione

In questo articolo, vedremo come applicare ad un controllo GridView di Asp.Net 4  un pannello di espansione, che visualizza altre informazioni per una determinata riga della griglia, il tutto come mostrato in figura 1.





Figura 1

Ogni riga della griglia, ha un immagine, che al click (sul simbolo piu) permette di visualizzare un pannello composto da controlli label, informazioni su quel determinato record.
Per ogni riga avremmo diversi dati, in riferimenti al codice id di quel record.
Supponendo di avere una tabella anagrafica, nella quale si trova un campo IdPersona, un campo nome ed un campo Cognome, in relazione ad un’altra tabella denominata Dettaglio persona con un campo nome ed un campo codice, oltre al campo id chiave e idpersona, della tabella anagrafica. In questo modo avremmo una relazione di tabelle, che possiamo applicare nella griglia.
Nel nostro articolo, utilizzeremo le classi, ma tale esempio si può utilizzare benissimo anche con fonti dati provenienti da un databse.

Creazione delle classi.

Si crea una classe di nome Persona e una di tipo DettaglioPersona. Nella classe presona,  si creano tre proprietà una di tipo intero (IdPersona) e due di tipo stirnga (nome e cognome) il tutto come riportato in nel codice qui sottostante.

VB.Net
Public Class Persona
    Public Property IDPersona As Int32
    Public Property Nome As String
    Public Property Cognome As String
End Class
C#
  public class Persona
    {
        public Int32 IDPersona { get; set; }
        public string Cognome { get; set; }
        public string Nome { get; set; }
    }


Mentre nella classe Dettaglio persona si crea una proprietà di tipo intero, denominata IdPersona, a cui sarà relazionata la classe Persona, due proprietà di tipo stringa, denominate rispettivamente Citta e Codice.
Qui di seguito si riporta il codice delle suddette dichiarazioni.

VB.Net
Public Class DettaglioPersona
    Public Property IDPersona As Int32
    Public Property Citta As String
    Public Property Codice As String
End Class
C# 
    public class DettaglioPersona
    {
        public Int32 IDPersona { get; set; }
        public string Citta { get; set; }
        public string codice { get; set; }
    }
}

Creazione della pagina ASPX.

Passiamo  in visualizzazione html per quanto riguarda la pagina ASPX, la funzione Espandi, permette di cambiare l’immagine di espansione e visualizzare o nascondere il panello, le immagini, sono state aggiunte al progetto.
Qui di seguito si riporta la funzione completa Javascript, che intercetta il pulsante e cambia l’immagine.

<script language="javascript" type="text/javascript">
    function espandi(obj, row) {
        var div = document.getElementById(obj);
        var img = document.getElementById('img' + obj);
        if (div != null) {
            if (div.style.display == "none") {
                div.style.display = "block";
                if (row == 'alt') {
                    img.src = "/meno.gif";
                }
                else {
                    img.src = "meno.gif";
                }
                img.alt = "Clicca per nascondere";
            }
            else {
                div.style.display = "none";
                if (row == 'alt') {
                    img.src = "/piu.gif";
                }
                else {
                    img.src = "/piu.gif";
                }
                img.alt = "Clicca per aprire";
            }
        }
    }
</script>




Aggiungiamo nella pagina web, un controllo gridView,  impostiamo l’evento OnRowDataBound, in modo che in tale evento, intercettiamo il singolo record ed aggiungiamo il pannello.
Si aggiungono quattro colonne, di tipo templateField, nella prima, impostiamo il codice per la visualizzazione delle immagini (visualizzare (meno) e nascondere (piu) ) e il relativo cambio. Due colonne contenenti il valore delle proprietà Nome e Cognome, ed una colonna in cui si crea una tabella html (table) contenente un controllo di tipo panel,  due controlli di tipo table lato server  ed un controllo di tipo label.

Qui di seguito si riporta il codice completo html del controllo gridview

<asp:GridView ID="GrvAnagrafica" runat="server" AutoGenerateColumns="False" DataKeyNames="IDPersona"
        OnRowDataBound="GrvAnagrafica_RowDataBound" CellPadding="4" ForeColor="#333333"
        GridLines="None">
        <AlternatingRowStyle BackColor="White" ForeColor="#284775" />
        <Columns>
            <asp:TemplateField>
                <ItemTemplate>
                    <a href="javascript:espandi('div<%# Eval("IDPersona") %>', 'one');">
                        <img id="imgdiv<%# Eval("IDPersona") %>" alt="Dettaglio informazioni" src="/piu.gif" />
                    </a>
                </ItemTemplate>
            </asp:TemplateField>
            <asp:TemplateField HeaderText="Nome" SortExpression="Nome">
                <ItemTemplate>
                    <asp:Label ID="lblNome" runat="server" Text='<%# Bind("Nome") %>'></asp:Label></ItemTemplate>
                <HeaderStyle HorizontalAlign="Left" />
            </asp:TemplateField>
            <asp:TemplateField HeaderText="Cognome" SortExpression="Cognome">
                <ItemTemplate>
                    <asp:Label ID="lblCognome" runat="server" Text='<%# Bind("Cognome") %>'></asp:Label></ItemTemplate>
                <ItemStyle HorizontalAlign="Center" />
            </asp:TemplateField>
            <asp:TemplateField>
                <ItemTemplate>
                    <tr>
                        <td colspan="100%">
                            <div id="div<%# Eval("IDPersona") %>">
                                <asp:Panel runat="server" ID="pnlSchedaDettaglio">
                                    <table id="Table1" runat="server">
                                        <tr>
                                            <td colspan="70">
                                                <asp:Label ID="Label1" runat="server" Text="Dettaglio Persona" Font-Bold="true" ForeColor="Red"></asp:Label>
                                            </td>
                                        </tr>
                                    </table>
                                    <asp:Table ID="tblSchedaDettaglio" runat="server">
                                    </asp:Table>
                                </asp:Panel>
                            </div>
                        </td>
                    </tr>
                </ItemTemplate>
            </asp:TemplateField>
            <asp:CommandField ShowEditButton="False" SelectText="Modifica" />
            <asp:CommandField ShowDeleteButton="False" />
        </Columns>
        <EditRowStyle BackColor="#999999" />
        <FooterStyle BackColor="#5D7B9D" Font-Bold="True" ForeColor="White" />
        <HeaderStyle BackColor="#5D7B9D" Font-Bold="True" ForeColor="White" />
        <PagerStyle BackColor="#284775" ForeColor="White" HorizontalAlign="Center" />
        <RowStyle BackColor="#F7F6F3" ForeColor="#333333" />
        <SelectedRowStyle BackColor="#E2DED6" Font-Bold="True" ForeColor="#333333" />
        <SortedAscendingCellStyle BackColor="#E9E7E2" />
        <SortedAscendingHeaderStyle BackColor="#506C8C" />
        <SortedDescendingCellStyle BackColor="#FFFDF8" />
        <SortedDescendingHeaderStyle BackColor="#6F8DAE" />
    </asp:GridView>

Il controllo table, visualizzerà i titoli e le varie righe, che andremmo a caricare dinamicamente, mentre il controllo label, le varie informazioni.

Stesura di codice

Ora passiamo in visualizzazione codice.
Si creano due funzioni, una che permetterà di valorizzare la griglia, e l’altra di visualizzare il dettaglio della singola riga.
Qui di seguito si riporta un esempio di codice delle due funzioni.

VB.Net
  Private Function CaricaDati() As List(Of Persona)
        'carico 2 dati di tipo persona
        Dim persone As New List(Of Persona)
        Dim pers As New Persona()
        pers.Cognome = "Mattei"
        pers.Nome = "Emanuele"
        pers.IDPersona = 1
        persone.Add(pers)
        pers = New Persona()
        pers.Cognome = "Mattei2"
        pers.Nome = "Emanuele2"
        pers.IDPersona = 2
        persone.Add(pers)
        Return persone
    End Function
    Private Function CaricaDettaglioPersona() As List(Of DettaglioPersona)
        Dim dettPersone As New List(Of DettaglioPersona)
        Dim DettPersona As New DettaglioPersona()
        DettPersona.Citta = "Roma"
        DettPersona.Codice = "AA"
        DettPersona.IDPersona = 1
        dettPersone.Add(DettPersona)
        DettPersona = New DettaglioPersona()
        DettPersona.Citta = "Firenze"
        DettPersona.Codice = "BB"
        DettPersona.IDPersona = 1
        dettPersone.Add(DettPersona)
        DettPersona = New DettaglioPersona()
        DettPersona.Citta = "Calabria"
        DettPersona.Codice = "CC"
        DettPersona.IDPersona = 2
        dettPersone.Add(DettPersona)
        Return dettPersone
    End Function
C#
private List<Persona> CaricaDati()
        {
            //carico 2 dati di persona
            List<Persona> persone = new List<Persona>();
            Persona pers = new Persona();
            pers.Cognome = "Mattei";
            pers.Nome = "Emanuele";
            pers.IDPersona = 1;
            persone.Add(pers);
            pers = new Persona();
            pers.Cognome = "Mattei2";
            pers.Nome = "Emanuele2";
            pers.IDPersona = 2;
            persone.Add(pers);
            return persone;
        }
        private List<DettaglioPersona> CaricaDettaglioPersona()
        {
            List<DettaglioPersona> dettPersone = new List<DettaglioPersona>();
            DettaglioPersona dettPersona = new DettaglioPersona();
            dettPersona.Citta = "Roma";
            dettPersona.codice = "AA";
            dettPersona.IDPersona = 1;
            dettPersone.Add(dettPersona);
            dettPersona = new DettaglioPersona();
            dettPersona.Citta = "Firenze";
            dettPersona.codice = "BB";
            dettPersona.IDPersona = 1;
            dettPersone.Add(dettPersona);
            dettPersona = new DettaglioPersona();
            dettPersona.Citta = "Calabria";
            dettPersona.codice = "CC";
            dettPersona.IDPersona = 2;
            dettPersone.Add(dettPersona);
            return dettPersone;
        }



Nell’evento load, valorizziamo la nostra riga, utilizzando la funzione CaricaPersona.
Qui di seguito si riporta il codice per l’evento load della form.

VB.Net
    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        Dim ListPersona As List(Of Persona) = CaricaDati()
        GrvAnagrafica.DataSource = ListPersona
        GrvAnagrafica.DataBind()
    End Sub
C#
        protected void Page_Load(object sender, EventArgs e)
        {
            List<Persona> listPersona = CaricaDati();
            GrvAnagrafica.DataSource = listPersona;
            GrvAnagrafica.DataBind();
        }

Terminata questa parte, si passa all’evento rowDataBound, in cui andremmo ad intercettare la creazione della singola riga, ed eseguire una query Linq, per relazionare le due classi, e caricare dinamicamente il pannello
Qui di seguito si riporta il codice delle suddette operazioni.

VB.Net
Protected Sub GrvAnagrafica_RowDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles GrvAnagrafica.RowDataBound
        If e.Row.RowType = DataControlRowType.DataRow Then
            'Rilevo la tabella delle schede reati
            Dim pnlSchedaDettaglio As Panel = e.Row.FindControl("pnlSchedaDettaglio")
            Dim tblSchedaDettaglio As Table = pnlSchedaDettaglio.FindControl("tblSchedaDettaglio")
            Dim valore As Int32 = CType(e.Row.DataItem, Persona).IDPersona
            Dim ListDetPersona As List(Of DettaglioPersona) = CaricaDettaglioPersona()
            Dim DettPersona = From pers In ListDetPersona
                              Where pers.IDPersona = valore
                              Select pers
            tblSchedaDettaglio.Width = New Unit("100%")
            'creo la riga
            Dim trRiga As New TableRow()
            tblSchedaDettaglio.Rows.Add(trRiga)
            'colonna Città - imposta i dati
            Dim TdColCitta As New TableCell()
            TdColCitta.Width = New Unit("15%")
            TdColCitta.Text = ""
            trRiga.Cells.Add(TdColCitta)
            'colonna Codice - imposta i dati
            Dim TdColCodice As New TableCell()
            TdColCodice.Width = New Unit("85%")
            TdColCodice.Text = ""
            trRiga.Cells.Add(TdColCodice)
            Dim ContaElementi As Int16 = 0
            For Each elemento In DettPersona
                trRiga = New TableRow()
                tblSchedaDettaglio.Rows.Add(trRiga)
                'colonna Città - imposta i dati
                TdColCitta = New TableCell()
                TdColCitta.Width = New Unit("15%")
                TdColCitta.Text = ""
                trRiga.Cells.Add(TdColCitta)
                'colonna Codice - imposta i dati
                TdColCodice = New TableCell()
                TdColCodice.Width = New Unit("85%")
                TdColCodice.Text = ""
                trRiga.Cells.Add(TdColCodice)
                tblSchedaDettaglio.Rows(ContaElementi + 1).Cells(0).Text = elemento.Citta
                tblSchedaDettaglio.Rows(ContaElementi + 1).Cells(1).Text = elemento.Codice
                ContaElementi += 1
            Next
        End If
    End Sub
C#
if (e.Row.RowType == DataControlRowType.DataRow)
            {
                //Rilevo la tabella delle schede reati
                Panel pnlSchedaDettaglio = e.Row.FindControl("pnlSchedaDettaglio") as Panel;
                Table tblSchedaDettaglio = pnlSchedaDettaglio.FindControl("tblSchedaDettaglio") as Table;
                 Int32 valore = ((Persona)e.Row.DataItem).IDPersona;
                List<DettaglioPersona> ListDetPersona = CaricaDettaglioPersona();
                var DettPersona = from pers in ListDetPersona
                                  where pers.IDPersona == valore
                                  select pers;
                     tblSchedaDettaglio.Width = new Unit("100%");
                        //creo la riga
                        TableRow trRiga = new TableRow();
                        tblSchedaDettaglio.Rows.Add(trRiga);
                        //colonna Città - imposta i dati
                        TableCell TdColCitta = new TableCell();
                        TdColCitta.Width = new Unit("15%");
                        TdColCitta.Text = "";
                        trRiga.Cells.Add(TdColCitta);
                        //colonna Codice - imposta i dati
                        TableCell TdColCodice = new TableCell();
                        TdColCodice.Width = new Unit("85%");
                        TdColCodice.Text = "";
                        trRiga.Cells.Add(TdColCodice);                  
                    //Creo le colonne dei titoli 
                    Label lblEtichettaCitta = new Label();
                    lblEtichettaCitta.Text = "Città";
                    lblEtichettaCitta.ID = "lblCitta";
                    tblSchedaDettaglio.Rows[0].Cells[0].Controls.Add(lblEtichettaCitta);
                    Label lblEtichettaTipoReato = new Label();
                    lblEtichettaTipoReato.Text = "Codice";
                    lblEtichettaTipoReato.ID = "lblCodice";
                    tblSchedaDettaglio.Rows[0].Cells[1].Controls.Add(lblEtichettaTipoReato);                   
                    Int16 ContaElementi = 0;
                    foreach (var elemento in DettPersona)
                    {
                         trRiga = new TableRow();
                        tblSchedaDettaglio.Rows.Add(trRiga);
                        //colonna Città - imposta i dati
                         TdColCitta = new TableCell();
                        TdColCitta.Width = new Unit("15%");
                        TdColCitta.Text = "";
                        trRiga.Cells.Add(TdColCitta);
                        //colonna Codice - imposta i dati
                         TdColCodice = new TableCell();
                        TdColCodice.Width = new Unit("85%");
                        TdColCodice.Text = "";
                        trRiga.Cells.Add(TdColCodice);
                        tblSchedaDettaglio.Rows[ContaElementi + 1].Cells[0].Text = elemento.Citta;
                        tblSchedaDettaglio.Rows[ContaElementi + 1].Cells[1].Text = elemento.codice;
                        ContaElementi += 1;
                    }              
            }
        }




Come si vede dal codice precedente, dopo aver rilevare l’oggetto panel, situato nella colonna della griglia, si crea un istanza della tabella contenuta al suo interno, in questo modo si crea una tabella, contenente i vari campi (titoli e valori)

Conclusioni

L’articolo ha voluto illustrare al lettore le basi per la creazione di una gridview con un pannello che integri le informazioni per ogni singola riga. Nell’esempio è stato utilizzato un controllo di tipo Label, ma nulla vieta che si possa inserire un controllo di tipo combobox, calendar, o altro.