Ripetitore che raggruppa elementi da un unico database

Nov 09 2020

Ho una tabella con intestazioni (esempio): Group, DisplayName, EditableData, description. Negli ultimi giorni ho cercato di imparare i ripetitori a ordinare le informazioni in base al gruppo in modo da poter ottenere qualcosa che assomiglia al seguente layout. Questo è un controllo utente che sto cercando di mettere insieme.

Group1
------------------
Name1     EditableData    Some Description
Name2     EditableData    Some Description

Group2
------------------
Name3     EditableData    Some Description
Name4     EditableData    Some Description

Ho guardato i seguenti altri esempi in linea: Ripetitori annidati - raggruppamento di dati e ripetitori annidati in ASP.NET

Credo di non capire bene come i ripetitori funzionino abbastanza per gestire l'annidamento o l'origine dati.

<asp:Repeater ID="Repeater1" runat="server">
    <ItemTemplate>
        Group: <%#Eval("Group")%><br />
        <%--Nested Repeater would go here for all the children info for each "Group"--%>
    </ItemTemplate>
</asp:Repeater>

Usare DISTINCT nel mio SQL per recuperare solo "Gruppo" mi lascia con i gruppi corretti senza ripetizioni e immagino che potrei semplicemente impostare i gruppi in etichette e poi creare ripetitori per ogni etichetta specifica ... Sembra terribile quando potrò più tardi update editableData torna al database.

Quello che voglio veramente credo sia almeno un collegamento a una procedura dettagliata che spiega come funzionano i ripetitori insieme a Eval () e alle origini dati. Voglio dire, il codice per fare tutto ciò di cui ho bisogno per completare questo primo passaggio nel mio progetto sarebbe perfetto; P Ma voglio anche essere in grado di capirli meglio perché probabilmente li userò spesso nel prossimo futuro.

Risposte

2 JamshaidK. Nov 09 2020 at 17:52

Una volta ho riscontrato lo stesso problema in cui dovevo ordinare i dati per gruppo e ho dovuto visualizzare gli elementi comuni in un segmento raggruppato.

Ci sono ovviamente diversi modi per recuperare i dati, ad esempio, puoi ottenere nomi di gruppi distinti e associarli al ripetitore e quindi ItemDataBoundall'evento puoi eseguire e ottenere altri elementi come questo:

<asp:Repeater runat="server" ID="rptrGroups" OnItemDataBound="rptrGroups_ItemDataBound">
    <ItemTemplate>
        <asp:Label runat="server" ID="lblGroupName" Text='<%# Eval("GroupName") %>' />

        <asp:GridView runat="server" ID="gv">
        </asp:GridView>
    </ItemTemplate>
</asp:Repeater>

protected void rptrGroups_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
    if (e.Item.ItemType == ListItemType.Item)
    {
        var lblGroupName = (Label)e.Item.FindControl("lblGroupName");
        GridView gv = (GridView)e.Item.FindControl("table");

        var dataTable = FetchDataWithGroupName(lblGroupName.Text); // Method that fetches data with groupname.
        gv.DataSource = dataTable;
        gv.DataBind();
    }
}

Questo non è un modo consigliato perché va al database, esegue query e quindi recupera i dati per ogni elemento (se stai recuperando questi dati da db). Se hai migliaia di gruppi, effettuerà chiamate al database migliaia di volte, il che è una cosa negativa.

La seconda soluzione è progettare un modello e fornire un modello personalizzato che farà il lavoro. Lascia che lo spieghi con un modello di esempio:

public class GroupedModel
{
    public string GroupName {get; set;}
    public List<NestedData> TableData {get; set;}
}
public class NestedData
{
    public string Id {get; set;}
    // Your columns here...
}

Quindi interroga e inizializza l'elenco della GroupedModelclasse, quindi invialo al file repeater. Fammi farlo con alcuni dati fittizi.

var tableData = new List<NestedData>();
var nestedData1 = new NestedData { Id = "1" };
var nestedData2 = new NestedData { Id = "2" };

tableData.Add(nestedData1);
tableData.Add(nestedData2);

var groupedModel = new GroupedModel 
{
    GroupName = "Group1",
    TableData = tableData
};

var listGroupedModel = new List<GroupedModel>();
listGroupedModel.Add(groupedModel);

rptrGroups.DataSource = listGroupedModel;

Quindi modifica il markup in questo modo:

<asp:Repeater runat="server" ID="rptrGroups">
    <ItemTemplate>
        <asp:Label runat="server" ID="lblGroupName" Text='<%# Eval("GroupName") %>' />

        <asp:GridView runat="server" ID="gv" DataSource='<%# ((GroupedModel)Container.DataItem).TableData %>'>
        </asp:GridView>
    </ItemTemplate>
</asp:Repeater>
1 AlbertD.Kallal Nov 09 2020 at 21:53

Trovo che usare solo una visualizzazione griglia o una visualizzazione elenco funzioni piuttosto bene. Tuttavia, NON tentare di utilizzare la funzione di raggruppamento, poiché è per posizionare gli elementi sulla pagina, non verso il basso.

Rendiamolo davvero semplice!

Ok, quindi ho un elenco di hotel, ma voglio raggrupparli per città.

Quindi, costruisci una query come questa:

    Dim strSQL As String = 
       "SELECT ID, FirstName, LastName, HotelName, City FROM tblHotels ORDER BY City, HotelName"

    GridView1.DataSource = Myrst(strSQL)
    GridView1.DataBind()

Ok, questo riempie la nostra visualizzazione a griglia. Otteniamo questo:

Finora, due righe di codice!

Ma vogliamo raggruppare per città.

Quindi a livello di classe dei moduli, aggiungi semplice var:

Public Class HotelGroupGrid
    Inherits System.Web.UI.Page

    Dim LastCity As String    <----- this one

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

        If IsPostBack = False Then
            LastCity = ""
            Call LoadGrid()
        End If
    End Sub

Ok, quindi ora sull'evento di associazione dell'elemento dati, aggiungi semplicemente una NUOVA riga.

Il codice ha questo aspetto:

    If e.Row.RowType = DataControlRowType.DataRow Then

        ' if grouping = 1 then create a new row!
        Dim gvRow As DataRowView = DirectCast(e.Row.DataItem, DataRowView)

        If gvRow("City") <> LastCity Then
            LastCity = gvRow("City")

            ' insert a new row for grouping header
            Dim MyRow As New GridViewRow(-1, -1, DataControlRowType.DataRow, DataControlRowState.Normal)
            Dim MyCel As New TableCell()
            'MyCel.Width = Unit.Percentage(100)
            Dim MyTable As Table = e.Row.Parent

            MyCel.ColumnSpan = MyTable.Rows(0).Controls.Count
            Dim MyLable As New Label
            MyLable.Text = "<h2>" & gvRow("City") & "</h2>"
            MyCel.Controls.Add(MyLable)
            MyRow.Cells.Add(MyCel)
            MyTable.Rows.AddAt(MyTable.Rows.Count - 1, MyRow)

        End If

    End If

Ora, sopra c'è un "pezzo" da masticare - ma ancora non molto codice.

Quindi, ora quando corriamo sopra, otteniamo questo:

Il nostro markup della vista griglia è simile a questo:

<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataKeyNames="ID">
  <Columns>
    <asp:BoundField DataField="City" HeaderText="City" InsertVisible="False" ReadOnly="True" SortExpression="ID" />
    <asp:BoundField DataField="ID" HeaderText="ID" InsertVisible="False" ReadOnly="True" SortExpression="ID" />
    <asp:BoundField DataField="FirstName" HeaderText="FirstName" SortExpression="FirstName" />
     <asp:BoundField DataField="LastName" HeaderText="LastName" SortExpression="LastName" />
     <asp:BoundField DataField="HotelName" HeaderText="HotelName" SortExpression="HotelName" />
   </Columns>
</asp:GridView>

Quindi, non troppo male.

Se decidi di utilizzare un listview? Quindi il codice diventa un po 'meno, ma il markup per listview è un bel po'.

Tutto ciò che facciamo è creare una riga che sia la nostra intestazione e ora mostrare o nascondere quella riga in base all'inizio del nuovo raggruppamento.

Quindi, se si decide di utilizzare una visualizzazione elenco? Quindi otteniamo questo:

(Presumo che tu usi le procedure guidate di ricerca dati - non stai digitando il markup a mano - giusto? - salvando la povertà nel mondo qui)

Quindi, per una visualizzazione elenco (e penso che la visualizzazione elenco sia MIGLIORE, poiché le opzioni di layout per quella riga di intestazione sono aperte a qualsiasi tipo di markup e controlli extra che sogni.

Quindi, il markup (generato e quindi tagliato il grasso) è questo:

<asp:ListView ID="ListView1" runat="server" DataKeyNames="ID">
    <EmptyDataTemplate>
        <table runat="server" style="">
           <tr><td>No data was returned.</td></tr>
        </table>
    </EmptyDataTemplate>
    <ItemTemplate>

       <tr id="GroupHeading" runat="server" style="display:none">
           <td colspan="4">
           <h2><asp:Label ID="City" runat="server" Text='<%# Eval("City") %>' /></h2>
           </td>
       </tr>

       <tr>
          <td><asp:Label ID="IDLabel" runat="server" Text='<%# Eval("ID") %>' /></td>
          <td><asp:Label ID="FirstNameLabel" runat="server" Text='<%# Eval("FirstName") %>' /></td>
          <td><asp:Label ID="LastNameLabel" runat="server" Text='<%# Eval("LastName") %>' /></td>
          <td><asp:Label ID="HotelNameLabel" runat="server" Text='<%# Eval("HotelName") %>' /></td>
       </tr>
   </ItemTemplate>

 <LayoutTemplate>
     <table id="itemPlaceholderContainer" runat="server" border="0" style="">
     <tr runat="server">
        <th runat="server">ID</th>
        <th runat="server">FirstName</th>
        <th runat="server">LastName</th>
        <th runat="server">HotelName</th>
    </tr>
    <tr id="itemPlaceholder" runat="server">
    </tr>

    </table>
 </LayoutTemplate>
 </asp:ListView>

Ora non c'è dubbio che listview emetta molti più markup, ma ora abbiamo una riga completa per l'intestazione. Quindi otteniamo questo:

Ma ora il nostro codice semplicemente nasconderà o mostrerà quella riga "extra" che abbiamo nel mercato.

Ed è abbastanza semplice ora:

If e.Item.GetType = GetType(ListViewDataItem) Then

  Dim MyRow As HtmlTableRow = e.Item.FindControl("GroupHeading")
  Dim lblCity As Label = MyRow.FindControl("City")
  If lblCity.Text <> LastCity Then
     LastCity = lblCity.Text
     ' Hide/show  group heading
     MyRow.Style("display") = "normal"
  Else
     MyRow.Style("display") = "none"
  End If

End If

Quindi il trucco nella maggior parte dei casi è semplicemente disporre l'elemento di riga in più, quindi sull'evento associato ai dati dell'elemento semplicemente nascondi o mostri quella parte di intestazione.