43

I have a repeater inside a repeater. Where the parent repeater is bound to a Datatble which has a column with a Datatable in it.

I would like to bind the child repeater to the datatable column in the parent repeater's datarow

Is this possible? i was thinking i could do this directly in the aspx file like:

DataSource="<%# DataBinder.Eval(Container.DataItem, "Products")%>" but it doesn't seem to work.

Jalal Said
  • 15,906
  • 7
  • 45
  • 68
bill
  • 905
  • 5
  • 10
  • 21

6 Answers6

82

In the parent repeater, attach a method to the OnItemDataBound event and in the method, find the nested repeater and data bind it.

Example (.aspx):

<asp:Repeater ID="ParentRepeater" runat="server" OnItemDataBound="ItemBound">
    <ItemTemplate>
        <!-- Repeated data -->
        <asp:Repeater ID="ChildRepeater" runat="server">
            <ItemTemplate>
                <!-- Nested repeated data -->
            </ItemTemplate>
        </asp:Repeater>
    </ItemTemplate>
</asp:Repeater>

Example (.cs):

protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        ParentRepeater.DataSource = ...;
        ParentRepeater.DataBind();
    }
}

protected void ItemBound(object sender, RepeaterItemEventArgs args)
{
    if (args.Item.ItemType == ListItemType.Item || args.Item.ItemType == ListItemType.AlternatingItem)
    {
        Repeater childRepeater = (Repeater)args.Item.FindControl("ChildRepeater");
        childRepeater.DataSource = ...;
        childRepeater.DataBind();
    }
}
Anton
  • 4,554
  • 2
  • 37
  • 60
  • Always find it odd when ItemDataBound is used for this. Is there any reason why you don't do it at the control level? – Kelsey May 27 '10 at 17:07
  • @Kelsey - this has always worked for me. No reason to do it otherwise. – Anton May 27 '10 at 17:23
  • 1
    see my answer for some advantages to using the controls `DataBinding` event instead. :) – Kelsey May 27 '10 at 17:34
  • 3
    you need to add arg.Item.ItemType == ListItemType.AlternatingItem in the if statement, otherwise you will skip items. – Kalel Wade Feb 21 '13 at 16:37
  • 2
    @KalelWade is right. Please fix this answer, the if shoold be `if (args.Item.ItemType == ListItemType.Item || args.Item.ItemType == ListItemType.AlternatingItem)` otherwise the code is not launched for every second item. – jakubiszon Mar 01 '13 at 10:25
  • @Jakub, I've edited the answer to include ListItemType.AlternatingItem. Good call. – Anton Mar 01 '13 at 18:18
  • 1
    What is used for childRepeater.DataSource = ...; ? I have a method but I need to send the parentID as an argument, but how do I access it? – Dejan Biljecki Aug 30 '13 at 19:28
26

I would add a DataBinding event to the child repeater itself:

<asp:Repeater ID="parentRepeater" runat="server">
    <asp:Repeater ID="childRepeater" runat="server"
        OnDataBinding="childRepeater_DataBinding" />
</asp:Repeater>

Then just implement it:

protected void childRepeater_DataBinding(object sender, System.EventArgs e)
{
    Repeater rep = (Repeater)(sender);

    int someIdFromParentDataSource = (int)(Eval("ParentID"));

    // Assuming you have a function call `GetSomeData` that will return
    // the data you want to bind to your child repeater.
    rep.DataSource = GetSomeData(int);
    rep.DataBind();
}

I prefer to do it at the control level instead of the ItemDataBound level so that if you ever have to remove controls or items within your templates you don't have to worry about looking for code in the parent controls that use it. It get's all localize witht he control itself. Plus you never have to do a FindControl.

If you want to replace a control in the future you can just delete it and your code will still work since it is all self contained. Using the ItemDataBound would cause your code to still compile but crash or act unexpectedly at runtime because of it's reliance on child controls.

Kelsey
  • 47,246
  • 16
  • 124
  • 162
  • so you add a databinding event to the child repeater? and how do i get the datasource?? which again is a row of type datatable from the parent control's datasource? thanks! – bill May 27 '10 at 17:07
  • @bill What information do you need from the parent datasource to get your new datasource? You have access to all the current rows information via the `Eval` function. I will update my answer to show an example. – Kelsey May 27 '10 at 17:10
  • the parent datasource is a datatable and it has a column in it that is a datable itself. At binding the child datasource is IN the parent datasource.. which is why i was thinking i could just bind in the ASPX file – bill May 27 '10 at 17:12
  • @bill You could try `rep.DataSource = (DataTable)(Eval("yourColumnWithTableInIt"))`. You have to be able to get the `DataTable` out of your original DataSource. – Kelsey May 27 '10 at 17:20
  • 8
    @Kelsey Your code do not work because it runs in recursive. While rep.DataBind(); is executed the event yourRepeater_DataBinding is raised. – Tomas Sep 21 '11 at 12:40
  • @Tomas no your missing how the `DataBinding` is working. You call `DataBind` on the top level `Repeater` and that contains another `Repeater` you implement the `OnDataBinding` on the inner `Repeater` so that when they top level one is bound, the `OnDataBinding` for the inner repeater fires and then you bind the inner `Repeater` item by item from the `OnDataBinding` event. I have editted by answer to make it more obvious. – Kelsey Jan 30 '12 at 15:26
  • 2
    Yes, I prefer to do it this way, for the reasons stated. In my app, doing a `DataBind()` causes an infinite loop; ASP seems to only need the `DataSource` to be set, without an explicit `DataBind()`, in order to work within the nested `Repeater`. – David R Tribble Sep 07 '12 at 19:45
  • 2
    @Kelsey: Thank you for this good answer, but in my code rep.DataBind() caused an infinite loop. I've removed it and everything is fine – 0xh8h Nov 25 '14 at 13:17
  • Thanks @Kelsey I like your solution better than using the ItemDataBound. Only thing I had to do is remove the rep.DataBind(); as it crashes my IIS. You should update your answer and take that line out. Thanks again! – Cesar Daniel Sep 10 '15 at 23:38
8

Here is how it's done:

DataSource='<%# ((System.Data.DataRowView)Container.DataItem)[3] %>'

So if you know the column in the parent table that holds the child table/datasource for the nested repeater you can put this directly in the aspx file.

Jason Berkan
  • 8,734
  • 7
  • 29
  • 39
bill
  • 905
  • 5
  • 10
  • 21
3

Repeater1 OnItemDataBound event, then FindControl Repeater2. The code-behind will not find the nested Repeater2! You have to use FindControl("Repeater2").

protected void Repeater1_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
    if (e.Item.DataItem != null)
    {
        MemberView dataRow = (MemberView)e.Item.DataItem;
        var cat = MemberPresenter.getMemberID(dataRow.memID);

        Repeater rp2 = (Repeater)e.Item.FindControl("Repeater2");
        rp2.DataSource = cat;
        rp2.DataBind();
    }  
}
Stephen Kennedy
  • 20,585
  • 22
  • 95
  • 108
Ravi Ram
  • 24,078
  • 21
  • 82
  • 113
2

If I need to do that, I usually do it using the ItemDataBound event of the parent repeater to bind the child repeater. If e is your EventArgs parameter, you'll have access to the child repeater via e.Item.FindControl(), and access to the data via e.Item.DataItem.

joelt
  • 2,672
  • 2
  • 24
  • 32
0
 protected void MainRepeater_ItemDataBound(object sender, RepeaterItemEventArgs args)
    {
         if (args.Item.ItemType == ListItemType.Item || args.Item.ItemType == ListItemType.AlternatingItem)
            {
                Repeater childRepeater = (Repeater)args.Item.FindControl("ChildRepeater");

                DataTable innerTable= ((DataRowView)args.Item.DataItem)["InnerTableColumnName"] as DataTable;
                childRepeater.DataSource = tasksDetails;
                childRepeater.DataBind();
            }
    }
Lev Z
  • 742
  • 9
  • 17