简体   繁体   English

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

[英]Repeater grouping items from single database

I have a table with headers(example): Group, DisplayName, EditableData, description.我有一个带有标题的表格(示例):Group、DisplayName、EditableData、description。 I have been trying for the last few days to learn repeaters to sort the information based on the Group so I can get something that looks like the following layout.在过去的几天里,我一直在尝试学习中继器根据组对信息进行排序,这样我就可以获得类似于以下布局的内容。 This is a user control I am trying to put together.这是我试图放在一起的用户控件。

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

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

I have looked a the following other examples online: Nested repeaters - grouping data and Nested Repeaters in ASP.NET我在网上查看了以下其他示例: 嵌套转发器 - ASP.NET 中的分组数据嵌套转发器

I believe I do not properly understand how repeaters work enough to deal with nesting or datasource.我相信我没有正确理解中继器如何工作以处理嵌套或数据源。

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

Using DISTINCT in my SQL to just retrieve "Group" leaves me with the proper groups without repeats and I guess I could just instead set the groups in labels and then later make repeaters for each specific label... This seems terrible when I may later update editableData back to the database.在我的 SQL 中使用 DISTINCT 来只检索“组”让我拥有正确的组而不会重复,我想我可以改为在标签中设置组,然后为每个特定标签制作中继器......这在我以后可能会很糟糕将 editableData 更新回数据库。

What I really want I guess is at least a link to a walkthrough that explains how repeaters work along with Eval() and datasources.我真正想要的是,我想至少有一个演练链接,它解释了中继器如何与 Eval() 和数据源一起工作。 I mean, code to do everything I need to complete this first step in my project would be perfect ;P But I also want to be able to understand these better as I am probably going to be using them often in the near future.我的意思是,完成项目第一步所需的所有代码都是完美的;P 但我也希望能够更好地理解这些,因为我可能会在不久的将来经常使用它们。

I once encountered the same issue where I was to sort the data by group and I had to display the common items in a grouped segment.我曾经遇到过同样的问题,我要按组对数据进行排序,并且必须在分组段中显示常见项目。

There are of-course multiple ways of how you retrieve data, for example, you can get Distinct Group Names and bind it to the repeater and then on ItemDataBound event you can execute and get other elements like this:当然,您可以通过多种方式检索数据,例如,您可以获取不同的组名称并将其绑定到转发器,然后在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();
    }
}

This is not a recommended way because it goes to database, runs query, and then fetches data for each item (if you are fetching this data from db).这不是推荐的方法,因为它进入数据库,运行查询,然后为每个项目获取数据(如果您从数据库获取此数据)。 If you have thousands of Groups then it will make db calls for thousands of times which is a bad thing.如果您有数千个组,那么它将进行数千次数据库调用,这是一件坏事。

The second solution is, you design a model and feed a custom model that will do the job.第二种解决方案是,您设计一个模型并提供一个自定义模型来完成这项工作。 Let me explain it by a sample model:让我通过一个示例模型来解释它:

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

Then query and initialize list of GroupedModel class then feed it to the repeater .然后查询并初始化GroupedModel类的列表,然后将其提供给repeater Let me do it with some dummy data.让我用一些虚拟数据来做。

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;

Then modify the markup like this:然后像这样修改标记:

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

I find that just using a gridview or list view works rather nice.我发现仅使用 gridview 或列表视图效果很好。 However, DO NOT attempt to use the grouping feature - as it is for placing items across the page, not down.但是,不要尝试使用分组功能 - 因为它用于在页面上放置项目,而不是向下放置。

Lets make this really simple!让这一切变得非常简单!

Ok, so I have a list of Hotels, but I want to group by city.好的,我有一个酒店列表,但我想按城市分组。

So, you build a query like this:所以,你构建一个这样的查询:

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

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

Ok, so that fills out our grid view.好的,这样就填充了我们的网格视图。 We get this:我们得到这个:

在此处输入图片说明

So far, two lines of code!到目前为止,两行代码!

But, we want to group by City.但是,我们想按城市分组。

So at the forms class level, add simple var:所以在表单类级别,添加简单的 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, so now on the data item bind event, simply add a NEW row.好的,现在在数据项绑定事件上,只需添加一个新行。

The code looks like this:代码如下所示:

    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

Now, above is a "bit" of a chunk to chew on - but still not a lot of code.现在,上面是一小块需要咀嚼的“位”——但仍然没有很多代码。

So, now when we run above, we get this:所以,现在当我们在上面运行时,我们得到:

在此处输入图片说明

Our grid view markup looks like this:我们的网格视图标记如下所示:

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

So, not too bad.所以,还不算太糟。

If you decide to use a listview?如果您决定使用列表视图? Then the code becomes quite a bit less, but the markup for listview is quite a handfull.然后代码变得少了很多,但是 listview 的标记非常少。

All we do is create a row that is our heading, and now show, or hide that row based on the start of new grouping.我们所做的就是创建一行作为我们的标题,然后根据新分组的开始显示或隐藏该行。

So, if one decides to use a list view?那么,如果决定使用列表视图呢? Then we get this:然后我们得到这个:

(I assume you use the databind wizards - your not possibly typing in the markup by hand - right? - saving world poverty here) (我假设您使用数据绑定向导-您不可能手动输入标记-对吗?-在这里拯救世界贫困)

So, for a list view (and I think the list view is BETTER, since the layout options for that heading row is wide open to any kind markup and extra controls you dream up.因此,对于列表视图(我认为列表视图更好,因为该标题行的布局选项对任何类型的标记和您梦寐以求的额外控件都是开放的。

So, the markup (generated - and then chopped out the fat) is this:所以,标记(生成 - 然后切掉脂肪)是这样的:

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

Now no question that the listview spits out a lot more markup - but we now have a full row for the heading.现在毫无疑问,列表视图会吐出更多标记 - 但我们现在有一个完整的标题行。 So we get this:所以我们得到这个:

在此处输入图片说明

But, now our code simply will hide or show that "extra" row we have in the marketup.但是,现在我们的代码将简单地隐藏或显示我们在市场上的“额外”行。

And it quite simple now:现在很简单:

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

So the trick in most cases is to simply layout that extra row item, and then on the item data bound event you simply hide or show that heading part.因此,大多数情况下的技巧是简单地布置该额外的行项目,然后在项目数据绑定事件上,您只需隐藏或显示该标题部分。

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

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