Solved

Problem using FindControl in a Nested Repeater

Posted on 2009-04-14
15
1,296 Views
Last Modified: 2012-06-21
I'm trying to reference a control in a nested repeater from within the outer repeater's ItemDataBound event.

1) I am assuming that this is possible.

2) I'm obviously not have much luck. While I understand that .FindControl has to be used on the correct container, I'm having problems executing it.

The following code successfully finds the nested repeater...

Dim InnerRepeater As Repeater = CType(e.Item.FindControl("RepeaterDelegates"), Repeater)
            Response.Write(InnerRepeater.ID)

However, when I try to get the control that I need, the control isn't found...

Dim NewTargetItem As Object
NewTargetItem = InnerRepeater.FindControl("DirectoryDetailDelegates")

In snooping around, I checked .HasControls on the inner repeater, it returned False which I thought was odd.
0
Comment
Question by:Mick87
  • 8
  • 6
15 Comments
 
LVL 8

Expert Comment

by:ppittle
ID: 24139478
Can you upload the Markup for the Repeators
0
 
LVL 39

Expert Comment

by:abel
ID: 24139686
Seems to me that either "e.Item" or "RepeaterDelegates" do not return you a Repeater control. Since you don't mention an error, I assume something is found. It might be, however, that the content of the inner repeater is not yet built.

Often, in these cases, it is much easier to react to events. If you have a control inside your repeater, register to the OnLoad event of it and do your thing from there.
0
 

Author Comment

by:Mick87
ID: 24140687
The object isn't set when I attempt to work with it.

I'm trying to alternate the items in the repeater by dynamically changing the CssClass using the ItemDataBound event. The idea is avoid having to use the <AlternateItemTemplate> and thus digging through two templates when I need to make a change. The code that I have does successfully alter the CssClass of the outer table. The innertable's CssClass needs to be altered to match that of the outertable.

While the underlying issue is using .FindControl on the inner repeater, the result is a nested table once rendered. The outer table has an image which shows/hides the nested table as needed.
<asp:Panel runat="server" CssClass="DirectoryPanel">

<asp:Repeater id="RepeaterDirectory" runat="server" DataSourceId="SqlDataSourceDirectory" onItemDataBound="RepeaterDirectory_onItemDataBound">

<ItemTemplate>

<!-- onRowDataBound programically alters the cssClass so that an AlternatingItemTemplate is not needed -->

<asp:Table ID="DirectoryDetail" runat="server" CssClass="DirectoryDetail">

<asp:TableRow ID="TableRow2" runat="server"></asp:TableRow>

<asp:TableRow>

<asp:TableCell ID="NestedRepeaterParentCell" runat="server" ColumnSpan="7">

<asp:repeater runat="server" Id="RepeaterDelegates" DataSourceID="SqlDataSourceDelegates" OnItemDataBound="RepeaterDelegates_onItemDataBound">

<ItemTemplate>

<asp:Table runat="server" Id="DirectoryDetailDelegates" CssClass="DirectoryDetailDelegates">

Open in new window

0
 
LVL 8

Expert Comment

by:ppittle
ID: 24140744
Mick87,

Try this.
<form id="form1" runat="server">       

        <asp:Repeater ID="RepeaterDirectory"

            runat="server" OnItemCreated="RepeaterDirectory_ItemCreated">

            <ItemTemplate>

                <asp:Table ID="DirectoryDetail" runat="server" CssClass="DirectoryDetail"

            </ItemTemplate>

        </asp:Repeater>

    </form>
 

<%-- Code Behind --%>

public partial class MyPage : System.Web.UI.Page

    {

        int rowCounter = 0;
 

        protected void Page_Load(object sender, EventArgs e)

        {

                

        }
 

        protected void RepeaterDirectory_ItemCreated(object sender, RepeaterItemEventArgs e)

        {

            Table table = (Table)e.Item.FindControl("DirectoryDetail");

            if (rowCounter++ % 2 == 0) //if (alternate row)

            {

                table.CssClass = "AlternateCSS";

            }

        }

    }

Open in new window

0
 
LVL 8

Expert Comment

by:ppittle
ID: 24140760
The trick is to use the Repeater's ItemCreated Event, which gives you a RepeaterItemEventArgs variable.  The RepeaterItemEventArgs has a Property, RepeaterItem, which is the Parent Control for all the Item Template.  So you can then find child controls using RepeaterItem.FindControl()
0
 

Author Comment

by:Mick87
ID: 24141193
Which ItemCreatedEvent - the ICE for the outer or inner repeater?

Also, intellisense isn't giving RepeaterItem as a vaild property for the e (the RepeaterItemEventArgs).


    Protected Sub RepeaterDirectory_onItemCreated(ByVal sender As Object, ByVal e As RepeaterItemEventArgs)

Open in new window

0
 
LVL 8

Expert Comment

by:ppittle
ID: 24141281
In you situation you want to handle the outer repeater's ItemCreatedEvent.  And the RepeaterItemEventArgs has a Property Item of type RepeaterItem.  Sorry for the ambiguity.
0
What Is Threat Intelligence?

Threat intelligence is often discussed, but rarely understood. Starting with a precise definition, along with clear business goals, is essential.

 

Author Comment

by:Mick87
ID: 24141556
I tried the snippet below, but once I get to Dim InnerRepeater [...] and check .HasControls the result is False. The structure is...

[Outer Repeater]
<Item Template>
[Outer Table]
        [Table Row]
        [Table Cell]
              [Inner Repeater]
              <Item Template>
              [Inner Table]

Where its the [Inner Table] that I need to find.
             
        If e.Item.ItemType = ListItemType.AlternatingItem Then

            Dim TargetItem As Object

            TargetItem = e.Item.FindControl("DirectoryDetail")

            TargetItem.CssClass = "DirectoryDetailAlternatingItem"

            Dim OuterTable As Table = CType(e.Item.FindControl("DirectoryDetail"), Table)

            Dim InnerRepeaterParentRow As Object = CType(OuterTable.FindControl("DetailRow3"), TableRow)

            Dim InnerRepeaterParentCell As Object = CType(InnerRepeaterParentRow.FindControl("NestedRepeaterParentCell"), TableCell)

            Response.Write(InnerRepeaterParentCell.GetType)

            Response.Write(InnerRepeaterParentCell.iD)

            Dim InnerRepeater As Object = CType(InnerRepeaterParentCell.FindControl("RepeaterDelegates"), Repeater)

            Response.Write(InnerRepeater.HasControls)

        End If

Open in new window

0
 
LVL 8

Expert Comment

by:ppittle
ID: 24142121
Mick87,

I didn't realize you were trying to change the CSS for both the parent table (DirectoyrDetail) AND the child table (DirectoryDetailDelegates).  For this case, the code snippet should take care of you.  

What's happening with the parent / child repeater that's confusing is when the parent ItemDataBound or ItemCreated event fires, the child repeater hasn't been built yet.  Which is why you can't find the controls in it yet.  Instead, you have to hook into the events for both the parent and the child repeaters.

PJ
<form id="form1" runat="server">       

        <asp:Repeater ID="RepeaterDirectory"

            runat="server" OnItemCreated="RepeaterDirectory_ItemCreated">

            <ItemTemplate>

                <asp:Table ID="DirectoryDetail" runat="server" CssClass="ParentTableCssClass">

                    <asp:TableRow>

                        <asp:TableCell ID="NestedRepeaterParentCell" runat="server">

                            <asp:Repeater ID="RepeaterDelegates" runat="server" OnItemCreated="RepeaterDirectory_ItemCreated">

                                <asp:Table ID="DirectoryDetailDelegates" CssClass="ChildTableCssClass" />

                            </asp:Repeater>

                        </asp:TableCell>

                    </asp:TableRow>

                </asp:Table>

            </ItemTemplate>

        </asp:Repeater>

    </form>
 

<%-- Code Behind --%>

public partial class Page : System.Web.UI.Page

    {

        protected void Page_Load(object sender, EventArgs e)

        {

                

        }
 

        protected void RepeaterDirectory_ItemCreated(object sender, RepeaterItemEventArgs e)

        {

            Table DirectoryDetailTable = (Table)e.Item.FindControl("DirectoryDetail");

            if (e.Item.ItemType == ListItemType.AlternatingItem)

            {

                DirectoryDetailTable.CssClass = "AlternateCSS";

            }

        }

        protected void RepeaterDelegates_ItemCreated(object sender, RepeaterItemEventArgs e)

        {

            Table DirectoryDetailDelegatesTable = (Table)e.Item.FindControl("DirectoryDetailDelegates");

            if (e.Item.ItemType == ListItemType.AlternatingItem)

            {

                DirectoryDetailDelegatesTable.CssClass = "AlternateCSS";

            }

        }

    }

Open in new window

0
 
LVL 8

Expert Comment

by:ppittle
ID: 24142144
Just realized I had a typo in the code snippet above.  The nested repeater (RepeaterDelegates) needs to call the RepeaterDelegates_ItemCreated method:

<asp:Repeater ID="RepeaterDelegates" runat="server"   OnItemCreated="RepeaterDelegates_ItemCreated">
                                <asp:Table ID="DirectoryDetailDelegates" CssClass="ChildTableCssClass" />
 </asp:Repeater>
0
 

Author Comment

by:Mick87
ID: 24142816
So in short, I can't do what I need to do solely using the events of the Parent. That I can deal with.
0
 

Author Comment

by:Mick87
ID: 24142829
But I'm assuming that if I want to use a minimum of code, to place it within the inner repeaters ItemCreated event and then go upwards to change the CssClass of the outer.
0
 
LVL 8

Accepted Solution

by:
ppittle earned 500 total points
ID: 24142935
There's not really a good event you can hook into for the Parent Repeater to modify the nested child elements.  I suppose if you really wanted to, you could hook into the PreRender event.  At the point in the ASP Page LifeCycle, all controls have been built (the HasControls property will be true for both the parent and child repeator).  However, the code would be rather nasty to get it to work, you'd have to walk through all child controls until you reached the child nested table.

Per your question about writting the minimum amount of code, I would advise against trying to do all of the work in one event handler.  You at least have to use the child repeators ItemCreated (or ItemDataBound) event, because the child repeater hasn't built out its controls when the parent repeator fire's its ItemCreated event.  However, if you try to write the code to manage the parent table (DirectoryDetail) from the child repeater's (RepeaterDelegates) ItemCreated event, you'll have to walk up the control collection and when you finally get a reference to your table, you'll have to figure out if it's in an alternate row in the parent repeater.

In the end the difference would proabably be less than 5 lines, so I'd argure for simplicity: use two seperate event handlers.  That way the logic is clearly divided and its easy to tell which table you are trying to manipulate.

PJ
0
 

Author Comment

by:Mick87
ID: 24144005
I ended up having to add code to the ItemDataBound events of both repeaters. While I was able to reference the outer table from the inner table, I realized that for whatever reason the outer repeater ItemDataBound events all fire before the inner repeater ItemDataBound events - using response.write. I didn't try the ItemCreate events. At any rate here's the final result...

    Protected Sub RepeaterDelegates_onItemDataBound(ByVal sender As Object, ByVal e As RepeaterItemEventArgs)

        Dim OuterTable As Table = CType(e.Item.Parent.Parent.Parent.Parent, Table)
        Response.Write(OuterTable.CssClass & "<br />")
        If OuterTable.CssClass = "DirectoryDetailAlternatingItem" Then
            Dim InnerTable As Table = CType(e.Item.FindControl("DirectoryDetailDelegates"), Table)
            InnerTable.CssClass = "DirectoryDetailDelegatesAlternatingItems"
        End If

    End Sub
    Protected Sub RepeaterDirectory_onItemDataBound(ByVal sender As Object, ByVal e As RepeaterItemEventArgs)

        Dim ExpandDelegates As Image = CType(e.Item.FindControl("ExpandDelegates"), Image)
        Dim CollapseDelegates As Image = CType(e.Item.FindControl("CollapseDelegates"), Image)
        Dim ContactId As Label = CType(e.Item.FindControl("ContactId"), Label)

        ExpandDelegates.Attributes.Add("onclick", "showDelegates 'GridViewDelegates_" + ContactId.Text + "', " + "'" + ExpandDelegates.ClientID + "', '" + CollapseDelegates.ClientID + "'")
        CollapseDelegates.Attributes.Add("onclick", "hideDelegates 'GridViewDelegates_" + ContactId.Text + "', " + "'" + ExpandDelegates.ClientID + "', '" + CollapseDelegates.ClientID + "'")

        Dim s As SqlDataSource = CType(e.Item.FindControl("SqlDataSourceDelegates"), SqlDataSource)
        Dim t As Label = CType(e.Item.FindControl("ContactId"), Label)
        s.SelectParameters(0).DefaultValue = t.Text

        If e.Item.ItemType = ListItemType.AlternatingItem Then
            Dim TargetItem As Object
            TargetItem = e.Item.FindControl("DirectoryDetail")
            TargetItem.CssClass = "DirectoryDetailAlternatingItem"
        End If

    End Sub
0
 
LVL 8

Expert Comment

by:ppittle
ID: 24144247
Good to hear you were able to find the solution.
0

Featured Post

Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

Lots of people ask this question on how to extend the “MembershipProvider” to make use of custom authentication like using existing database or make use of some other way of authentication. Many blogs show you how to extend the membership provider c…
International Data Corporation (IDC) prognosticates that before the current the year gets over disbursing on IT framework products to be sent in cloud environs will be $37.1B.
This video discusses moving either the default database or any database to a new volume.
This video demonstrates how to create an example email signature rule for a department in a company using CodeTwo Exchange Rules. The signature will be inserted beneath users' latest emails in conversations and will be displayed in users' Sent Items…

758 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

18 Experts available now in Live!

Get 1:1 Help Now