繁体   English   中英

来自单个数据库的中继器分组项目

[英]Repeater grouping items from single database

我有一个带有标题的表格(示例):Group、DisplayName、EditableData、description。 在过去的几天里,我一直在尝试学习中继器根据组对信息进行排序,这样我就可以获得类似于以下布局的内容。 这是我试图放在一起的用户控件。

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

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

我在网上查看了以下其他示例: 嵌套转发器 - ASP.NET 中的分组数据嵌套转发器

我相信我没有正确理解中继器如何工作以处理嵌套或数据源。

<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>

在我的 SQL 中使用 DISTINCT 来只检索“组”让我拥有正确的组而不会重复,我想我可以改为在标签中设置组,然后为每个特定标签制作中继器......这在我以后可能会很糟糕将 editableData 更新回数据库。

我真正想要的是,我想至少有一个演练链接,它解释了中继器如何与 Eval() 和数据源一起工作。 我的意思是,完成项目第一步所需的所有代码都是完美的;P 但我也希望能够更好地理解这些,因为我可能会在不久的将来经常使用它们。

我曾经遇到过同样的问题,我要按组对数据进行排序,并且必须在分组段中显示常见项目。

当然,您可以通过多种方式检索数据,例如,您可以获取不同的组名称并将其绑定到转发器,然后在ItemDataBound事件上您可以执行并获取其他元素,如下所示:

<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();
    }
}

这不是推荐的方法,因为它进入数据库,运行查询,然后为每个项目获取数据(如果您从数据库获取此数据)。 如果您有数千个组,那么它将进行数千次数据库调用,这是一件坏事。

第二种解决方案是,您设计一个模型并提供一个自定义模型来完成这项工作。 让我通过一个示例模型来解释它:

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...
}

然后查询并初始化GroupedModel类的列表,然后将其提供给repeater 让我用一些虚拟数据来做。

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;

然后像这样修改标记:

<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>

我发现仅使用 gridview 或列表视图效果很好。 但是,不要尝试使用分组功能 - 因为它用于在页面上放置项目,而不是向下放置。

让这一切变得非常简单!

好的,我有一个酒店列表,但我想按城市分组。

所以,你构建一个这样的查询:

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

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

好的,这样就填充了我们的网格视图。 我们得到这个:

在此处输入图片说明

到目前为止,两行代码!

但是,我们想按城市分组。

所以在表单类级别,添加简单的 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

好的,现在在数据项绑定事件上,只需添加一个新行。

代码如下所示:

    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

现在,上面是一小块需要咀嚼的“位”——但仍然没有很多代码。

所以,现在当我们在上面运行时,我们得到:

在此处输入图片说明

我们的网格视图标记如下所示:

<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>

所以,还不算太糟。

如果您决定使用列表视图? 然后代码变得少了很多,但是 listview 的标记非常少。

我们所做的就是创建一行作为我们的标题,然后根据新分组的开始显示或隐藏该行。

那么,如果决定使用列表视图呢? 然后我们得到这个:

(我假设您使用数据绑定向导-您不可能手动输入标记-对吗?-在这里拯救世界贫困)

因此,对于列表视图(我认为列表视图更好,因为该标题行的布局选项对任何类型的标记和您梦寐以求的额外控件都是开放的。

所以,标记(生成 - 然后切掉脂肪)是这样的:

<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>

现在毫无疑问,列表视图会吐出更多标记 - 但我们现在有一个完整的标题行。 所以我们得到这个:

在此处输入图片说明

但是,现在我们的代码将简单地隐藏或显示我们在市场上的“额外”行。

现在很简单:

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

因此,大多数情况下的技巧是简单地布置该额外的行项目,然后在项目数据绑定事件上,您只需隐藏或显示该标题部分。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM