I constructed a Repeater for my XML file roughly like so:
<asp:XmlDataSource ID="XmlDataSource1" runat="server" DataFile="samplexml.xml" XPath="level1/level2" />
<asp:Repeater id="category" runat="server" DataSourceID="XmlDataSource1">
<ItemTemplate>
<div class="category">
<h2><%#XPath("#name") %></h2>
<asp:Repeater id="group" runat="server" DataSource='<%# XPathSelect("group") %>'>
<ItemTemplate>
...
</ItemTemplate>
</asp:Repeater>
</div>
</ItemTemplate>
</asp:Repeater>
And now I'm working on how to get the data inside of each on postback. I learned roughly how to get into a RepeaterItem:
foreach (RepeaterItem items in category.Items)
{
Output.Text += items.UniqueID + "<br />";
}
But after a lot of searching MSDN, this site, and others, I haven't been able to figure out how to get into the group repeater.
Am I missing something obvious here? I'm in .NET 2.0.
You aren't missing anything obvious. In my experience working with nested Repeaters/ListViews/Etc is a nightmare.
If you have the option to do this using MVC I would recommend that. If not.... Your best bet is probably to get familiar with FindControl. Typically your code will look something like this:
protected void category_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
Repeater level2 = e.Item.FindControl("group") as Repeater;
//you are now working with the nested repeater in a single row... Do what you will!
}
So when a row in the parent repeater binds, you will have to use FindControl to find it's nested repeater. Good luck!
Related
I have an issue with nested Gridview!
I have two Girdviews with the ID - GridView1(Parent Gridview) and GV2(Child Gridview)
I have a Asp:Button with the ID - btnedit(Event = OnClick())
Qs: how to access GV2 in btnedit_Onclick event?
I have attached the Code for your Reference:
<form id="form1" runat="server">
<asp:Button runat="server" ID="btnedit" Text="Edit" OnClick="btnedit_Click" />
<asp:GridView runat="server" ID="Gridview1">
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:Label runat="server" ID="Lable1"></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField>
<ItemTemplate>
<asp:GridView runat="server" ID="GV2">
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:Label runat="server" ID="Lable2"></asp:Label>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</form>
code Behind:
protected void btnedit_Click(object sender, EventArgs e)
{
}
Ok, so the user wants to operate on the row 1 of main GV and then get row 1 of the child.
Gridviews start at 0, so it not clear, but lets take the both first rows.
next up? I really (but really really really) suggest you use a main listview and then nest a child GV.
If you nest two GV's, you tend to get this:
Say this GV, with a "+" to expand the child grid:
And expanding, you get this:
So, nesting grids is VERY hard, since the "col span" is hard to setup.
However, if I build a main listview (looks the same as a GV), and then next a gv, then I get this:
So above uses a main list view, and thus for expanding child reocrds I do and did use a GV in the child of the listview.
I can post how above works and even the markup if you wish.
However, lets go with the two nested GV's - it will make a mess of a UI but for learning, how this works with the above nested LV + GV, or a GV + GV is the same.
So, some plane jane button - outside of the two grids, get the first row of the main, then the first row of the child grid.
This works:
protected void Button1_Click(object sender, EventArgs e)
{
GridViewRow MainGvRow = GridView1.Rows[0];
GridView ChildGV = MainGvRow.FindControl("GridView2") as GridView;
GridViewRow ChildGVRow = ChildGV.Rows[0]
}
This may get you started...
GridView gvGV2 = e.Row.FindControl("GV2") as GridView;
gvGV2.DataSource = "..."; //Your DataSource
gvGV2.DataBind();
// or do something else.
I'm sure there's a really simple explanation for this but I've been tearing my hair out too long now so I appeal to SO for the sake of my sanity!
It's this simple: I have a ListView which is bound when the page first loads (and not again on postback). It's part of a form. On the first load I see the list of items but when I postback I see the EmptyDataTemplate. Is this correct behaviour? I'm sure that ListView as a data binding control should persist its list over postbacks. Here's the code, first front end:
<asp:ListView ID="boxes" runat="server" ItemType="Model.Generic.ILookupEntity<int>" EnableViewState="true">
<LayoutTemplate>
<div>
<ul class="contact-list checkbox-row">
<li id="itemPlaceholder" runat="server" />
</ul>
</div>
</LayoutTemplate>
<ItemTemplate>
<li>
<label>
<asp:CheckBox ID="cb" runat="server" />
<asp:HiddenField ID="value" runat="server" Value="<%# Item.Key %>" />
<span><%# Item.Value %></span>
</label>
</li>
</ItemTemplate>
<EmptyDataTemplate>
<p>No data</p>
</EmptyDataTemplate>
</asp:ListView>
<asp:CheckBoxList ID="boxtemp" runat="server" />
Then back end:
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
if (!IsPostBack)
{
var items = new List<Model.Generic.LookupEntity<int>>()
{
new Model.Generic.LookupEntity<int>(1, "One"),
new Model.Generic.LookupEntity<int>(2, "Two"),
new Model.Generic.LookupEntity<int>(3, "Three"),
new Model.Generic.LookupEntity<int>(4, "Four"),
};
boxes.DataSource = items;
boxes.DataBind();
boxtemp.DataSource = items;
boxtemp.DataTextField = "Value";
boxtemp.DataValueField = "Key";
boxtemp.DataBind();
}
}
I've added the boxtemp CheckBoxList as a test. This one retains its data on postback. But the ListView doesn't. What am I doing wrong here?
UPDATE 1
What's even weirder is that if I add the following code and debug, the variable test references the value 4 even on postback. But when the posted page is rendered I still see the EmptyItemTemplate.
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
var test = boxes.Items.Count;
}
UPDATE 2
Having had it confirmed that this is not expected behaviour I have now found the cause I think. The ListView is inside a user control which is calling this.DataBind() on PreRender. I presume this is causing all data bound controls inside to re-bind on postback. The weird thing is that if I handle the ListView's OnDataBinding and OnDataBound events, on post back I can observe that the list still contains 4 items during both events. But is still rendered displaying the EmptyDataTemplate. Given this scenario, and assuming that the parent control's DataBind call is required, can anyone suggest the best resolution?
I have a survey composed of nested repeater objects of questions that are within subjects. Everything is populated dynamically via the database. Each question has a radiobuttonlist of answers. There can be one or many questions per subject. When the user complete the form and click submit, how does my click function loop through all controls, find each radiobuttonlist and its' selected answer?
<div id="qDiv" runat="server" >
<asp:Repeater runat="server" ID="rptSubject" OnItemDataBound="rptSubject_ItemDataBound">
<ItemTemplate>
<h2><%#DataBinder.Eval(Container.DataItem, "Subject")%></h2>
<asp:Repeater runat="server" ID="rptQuestion" OnItemDataBound="rptQuestion_ItemDataBound">
<ItemTemplate>
<p><%# DataBinder.Eval(Container.DataItem, "Question")%></p>
<asp:RadioButtonList ID="rblAnswers" runat="server"></asp:RadioButtonList>
</ItemTemplate>
</asp:Repeater>
</ItemTemplate>
</asp:Repeater>
</div>
protected void submitButton_Click(object sender, EventArgs e)
{
???
}
As well as the selected answer, can I also get access to the repeaters values question & subject in the click function?
Use the Page.FindControl(string) method to find server controls based on a known ID pattern.
I am working with a two nested data repeaters, and I want to allow paging for the outer repeater.
Here is what I have so far:
<asp:Repeater ID="Repeater1" runat="server" DataSourceID="LinqDataSource1" OnItemDataBound="Repeater1_ItemDataBound">
<HeaderTemplate>
<div class="group">
</HeaderTemplate>
<ItemTemplate>
<div class="question"><%#Eval("QText") %></div>
<asp:HiddenField ID="HiddenField1" runat="server" Value='<%# setQID(Eval("QID"))%>' />
<%-- THE INNER REPEATER--%>
<asp:Repeater ID="Repeater1" runat="server" DataSourceID="LinqDataSource2">
<HeaderTemplate>
<div class="answer">
</HeaderTemplate>
<ItemTemplate>
<%# (GetAnswer(Eval("AnsQID"))) != 1 ? (displayAnswer(Eval("AText"))) : ""%>
</ItemTemplate>
<FooterTemplate>
</div>
</FooterTemplate>
</asp:Repeater>
<%-- THE INNER REPEATER ENDS HERE--%>
</ItemTemplate>
<FooterTemplate>
</div>
</FooterTemplate>
</asp:Repeater>
I have googled for this, searched everywhere and found a lot of ways to approach this. I am using LinqDatasources and two repeaters. What is the best way to do this ?
To page the outer repeater i have used the method outlined in this post in the past. I don't think it should make much difference to the outcome if your repeater is nested. Your inner repeater will count as one row.
Repeaters generally though don't have great support for paging. You could consider using ListView (if using ASP.Net 3.5 or greater) or GridView (ASP.Net 2.0 or greater) which have more support for paging out of the box.
I have used this control in my Project.
http://www.codeproject.com/KB/custom-controls/CollectionPager.aspx
optional
http://www.codeproject.com/KB/webforms/SQLPager_For_Everything.aspx
and for Nested you have to use Databoud event and bound the child repeater.
I have a list of parents, that have children. I am trying to output this on my website doing the following. It works, but is it right? What is the best alternative?
<ul id="example">
<asp:Repeater ID="monkey" runat="server" >
<ItemTemplate>
<li>
<span class="folder">
<%# GetPlantName((string)Container.DataItem) %>
</span>
<ul>
<asp:Repeater id="moo" runat="server" DataSource="<%# GetTagList((string)Container.DataItem) %>">
<ItemTemplate>
<li>
<asp:LinkButton ID="d" runat="server" Text='<%# Eval("ReportNo")%>'></asp:LinkButton>
</li>
</ItemTemplate>
</asp:Repeater>
</ul>
</li>
</ItemTemplate>
</asp:Repeater>
</ul>
Nested repeaters are acceptable. Just be careful with things like RowDataBound events. It's not always obvious, especially to junior developers, that these methods are essentially nested loops. I've seen mistakes like a trip to the database in the nested repeater, which results in a lot of overhead.
Just keep in mind that what you're doing is essentially a nested loop and design code accordingly and it's perfectly fine.
I hope no
I have a repeater in a repeater in a repeater in a repeater in something :-p
No, it is not wrong! On the contrary, it is what we have to do more often than not.
Sometimes there are better solutions but that always depends on the requirements.
hth,
\ ^ / i l l
I see nothing wrong here at all. You have a list (repeater 1) with a nested list (repeater 2).
Is it wrong? No. It's only 'wrong' (and that's basically a pseudonym for inefficient) if you plan on doing something with a repeater that could be done easier with something else.