Using Nested Repeaters With Stored Procedures - asp.net

Hey I would like to use Nested Stored Procedures in ASP.NET 2.
The first stored procedure returns all Campains and second one returns all items in the campaigns.
I have my 2 repeaters set up, and now I am trying to pass a parameter from the parent repeater to child repeater stored procedure i.e campaign id....this proving tricky
In the code behind I wanted to try
public void Repeater1_ItemDataBound(Object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType ==
ListItemType.AlternatingItem || e.Item.ItemType == ListItemType.EditItem)
{
SqlDataSource2.SelectParameters["campaignId"].DefaultValue =
DataBinder.Eval(e.Item.DataItem, "campaignId").ToString();
}
}
But I dont know how to call this method or get it to load if I try this
<asp:Repeater ID="Repeater1" runat="server" DataSourceID="SqlDataSource1" OnDataBinding="Repeater1_ItemDataBound">
I get the error
CS0123: No overload for 'Repeater1_ItemDataBound' matches delegate 'System.EventHandler'
Any help would be greatly appreciated
EDIT : Changed mY Code Behind to
public void Repeater1_ItemDataBound(Object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType ==
ListItemType.AlternatingItem || e.Item.ItemType == ListItemType.EditItem)
{
Response.Write(DataBinder.Eval(e.Item.DataItem, "campaignId").ToString());
SqlDataSource2.SelectParameters["campaignId"].DefaultValue =
DataBinder.Eval(e.Item.DataItem, "campaignId").ToString();
SqlDataSource2.SelectParameters["statusId"].DefaultValue =
"1";
}
foreach (RepeaterItem repeaterItem in Repeater1.Items)
{
((Repeater)(repeaterItem.FindControl("Repeater2"))).DataBind();
}
}
But no joy its passing the correct campaign id to the stored procedure but this isnt displayed correctly on front end
any ideas ?

Instead of trying to attach the DataBinding event, you should be attaching the ItemDataBound event:
<asp:Repeater ID="Repeater1" runat="server"
DataSourceID="SqlDataSource1" OnItemDataBound="Repeater1_ItemDataBound">
The DataBinding event is for the whole repeater, the ItemDataBound will fire per item.

Microsoft publish an step by step guide to display hierarchical data using Nested Repeater Controls: Display Hierarchical Data
Remember that it is posible to return two datasets from a Store Procedure (An store procedure that ends with two SELECTs)
This is an example using EnterpriseLibrary
Try
Using cmd As DbCommand = db.GetStoredProcCommand("spYourStoreProcedure")
db.AddInParameter(cmd, "#customer", DbType.Int32, nCustomer)
Using ds = db.ExecuteDataSet(cmd)
ds.Tables(0).TableName = "Parent"
ds.Tables(1).TableName = "Child"
ds.Relations.Add("MyRelation", ds.Tables("Parent").Columns("customer"), ds.Tables("Child").Columns("customer"))
ParentRepeater.DataSource = ds.Tables("Parent")
ParentRepeater.DataBind()
End Using
End Using
Catch ex As Exception
' Manage your excepion
Exit Sub
End Try
This is a simple nested repeater:
<asp:Repeater ID="ParentRepeater" runat="server">
<HeaderTemplate>
<ul>
</HeaderTemplate>
<ItemTemplate>
<li>
<b><%# Container.DataItem("customer_name")%></b>
<asp:Repeater ID="repFuncionesXArea" runat="server" DataSource='<%# Container.DataItem.Row.GetChildRows("MyRelation") %>' >
<HeaderTemplate>
<ul>
</HeaderTemplate>
<ItemTemplate>
<li><%# Container.DataItem("customer_history")%></li>
</ItemTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:Repeater>
</li>
</ItemTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:Repeater>

Related

Nested repeater and datasource

I have a repeater nested in an other repeater.
My question is: is it possible to generate other ItemTemplate components with datasource.
If yes, how can I do it ?
For example:
ItemTemplate1 of parentRepeater
A
B
C
ItemTemplate2 of parentRepeater
D
E
F
It means that ItemTemplate of childRepeater is changed for each ItemTemplate of parentRepeater.
<asp:Repeater runat="server" ID="repeater1"
onitemdatabound="Repeater1_ItemDataBound" >
<ItemTemplate>
<!--Outer repeater -->
<asp:repeater id="repeater2" runat="server">
<itemtemplate>
<!--Inner repeater repeater -->
</itemtemplate>
</asp:repeater>
</ItemTemplate>
</asp:Repeater>
`
Here is Back end code
protected void Repeater1_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
//it return current row (think in terms of nested loops)
DataRowView drv = (DataRowView)e.Item.DataItem;
// get value of that row
int postID = Convert.ToInt32(drv["PostID"]);
//do what ever you want to do
Repeater2.DataSource = //some data like you did in outer repeater
Repeater2.DataBind();
}
}
If your goal is to have them alternate back and forth between two templates, then use AlternateItemTemplate.
<asp:Repeater runat="server">
<ItemTemplate>
This came from ItemTemplate.
</ItemTemplate>
<AlternateItemTemplate>
This came from AlternateItemTemplate.
</AlternateItemTemplate>
</asp:Repeater>
This is commonly used when you want to vary the background color of each row in a table.

Nested Repeater HeaderTemplate issue

Hello i am using nested repeaters (3 levels) and wanted to add header to a second level repeater, so I could assign title for item group. The issue is, when I add header template to second level repeater, my code behind can't find third level repeater. Even if header template is empty the issue still persists. Does anyone have any suggestions?
<asp:Repeater runat="server" ID="rpt2nd" OnItemDataBound="rpt2nd_OnDataBound">
<HeaderTemplate></HeaderTemplate>
<ItemTemplate>
<asp:Repeater runat="server" ID="rpt3rd">
<ItemTemplate></ItemTemplate>
</asp:Repeater>
</ItemTemplate>
</asp:Repeater>
protected void rpt2nd_OnDataBound(object sender, RepeaterItemEventArgs e)
{
var rpt3rd= ((Repeater)e.Item.FindControl("rpt3rd"));
rpt3rd.DataSource = ((KeyValuePair<int, IEnumerable<CustomClass>>)e.Item.DataItem).Value;
rpt3rd.DataBind();
}
You need to add if(e.Item.ItemType != ListItemType.Item && e.Item.ItemType != ListItemType.AlternatingItem) return; to the top of the rpt2nd_OnDataBound (also, it should be renamed to rpt2nd_OnItemDataBound to avoid confusion).

Why is my ASP.NET Repeater data not available in load events via code behind?

I have an ASP.NET repeater that is being populated via a datasource. The data loads and presents perfectly on the screen, but all attempts to access any row of data in that repeater via code behind during the load phase are unsuccessful. I can access everything perfectly on a form submit, once the repeater has rendered on the screen, but in every load-related event I have tried (Load, Init, PreRender, DataBind, etc), it shows as empty. Is it necessary to populate the repeater programatically in code behind, rather than ASPX markup, in order to access this data during the load phase or am I just doing something wrong?
ASPX snippet:
<div runat="server" id="rpt3" style="display: block;">
<p class="approvalHeaderText">
Rejected Items</p>
<asp:Repeater ID="RptRejected" runat="server" DataSourceID="SQL_EmployeeGetRejectedEdits">
<ItemTemplate>
<tr class="gridToggleWhite gridVisible" id="<%# Eval("RecID") %>_cont">
<td>
<%# Eval("OrderID")%>
</td>
Code behind snippet - tried in several events (assume all variables have been declared):
For i = 0 To RptRejected.Items.Count - 1
'Obtain current week's Expenses
curExpVal = RptRejected.Items(i).FindControl("ExpensePay")
If Not IsNothing(curExpVal) Then
If curExpVal.Text = "" Then
insertExp = 0
Else
insertExp = CSng(curExpVal.Text)
End If
Else
insertExp = 0
End If
Next
You can use the ItemDataBound event (and you don't need the loop):
Sub rpt3_ItemDataBound(Sender As Object, e As RepeaterItemEventArgs)
If (e.Item.ItemType = ListItemType.Item) OrElse _
(e.Item.ItemType = ListItemType.AlternatingItem) Then
Dim curExpVal = e.Item.FindControl("ExpensePay")
If Not IsNothing(curExpVal) Then
If curExpVal.Text = "" Then
insertExp = 0
Else
insertExp = CSng(curExpVal.Text)
End If
Else
insertExp = 0
End If
End If
End Sub
R1_Load and R1_ItemDataBound should be used to populate your data and R1_ItemCommand should be used to handle the button actions.
aspx
<asp:Repeater runat="server" ID="R1" OnItemCommand="R1_ItemCommand" OnItemDataBound="R1_ItemDataBound"
OnLoad="R1_Load">
<HeaderTemplate>
<table>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td>
<asp:TextBox runat="server" ID="txt"></asp:TextBox><asp:Button runat="server" ID="btn"
Text="Add" CommandName="AddOne" />
</td>
</tr>
</ItemTemplate>
<FooterTemplate>
</table> </FooterTemplate>
</asp:Repeater>
aspx.cs
protected void R1_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
var items = new List<int>();
for (int i = 0; i < 5; i++)
{
items.Add(i);
}
R1.DataSource = items;
R1.DataBind();
}
}
protected void R1_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
var txt = e.Item.FindControl("txt") as TextBox;
txt.Text = Convert.ToString(e.Item.DataItem);
}
}
protected void R1_ItemCommand(object source, RepeaterCommandEventArgs e)
{
if (e.CommandName == "AddOne")
{
var txt = e.Item.FindControl("txt") as TextBox;
txt.Text = (Convert.ToInt32(txt.Text) + 1).ToString();
}
}
My key mistake was using Eval() instead of the DataBinder.Eval() method. While the result is the same on the screen, Eval() does not trip the OnItemDataBound event. Once I switched my markup over to DataBinder.Eval(), everything fell into place. Thanks, everyone, for your ideas.

how to find repeater inside another repeater

I want to find repeater inside the another repeater. But i m not able to find. My code is
<asp:Repeater ID="rep_test" runat="server">
<ItemTemplate>
<div id='h<%# DataBinder.Eval(Container, "ItemIndex") %>' class="header" onclick='ToggleDisplay(<%# DataBinder.Eval(Container, "ItemIndex") %>);'>
<%#DataBinder.Eval(Container.DataItem, "ID")%>
</div>
<div id='d<%# DataBinder.Eval(Container, "ItemIndex") %>' class="details">
<asp:Repeater ID="rep_hello" runat="server">
<ItemTemplate>
<%#DataBinder.Eval(Container.DataItem, "batchid")%><br />
<%#DataBinder.Eval(Container.DataItem, "ts")%><br />
</ItemTemplate>
</asp:Repeater>
<%-- <%#DataBinder.Eval(Container.DataItem, "batchid")%><br />
<%#DataBinder.Eval(Container.DataItem, "ts")%><br />--%>
</div>
</ItemTemplate>
</asp:Repeater>
If you put a repeater inside an item template of another repeater that means that every item of the main repeater (rep_test) will have a repeater inside it (rep_hello). So you actually need to find the repeater inside a repeaterItem. You can iterate trough all the nested repeaters like this:
foreach (RepeaterItem item in rep_test)
Repeater rptr = (Repeater)item.FindControl("rep_hello");
Example:
In ItemDataBound event handler:
protected void rep_test_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
(e.Item.FindControl("rep_hello") as Repeater).DataSource = YourOtherDataSource;
}
}
You can try using .FindControl(). In VB, it would be something like
Dim rpt as Repeater = rep_test.FindControl("rep_hello")
Usually when I see this kind of thing, you want to perform some event on all of the inner repeaters. What I usually do is handle this kind of thing inside the ItemDataBound event.
Add an OnItemDataBound attribute to your Repeater.
<asp:Repeater ID="rep_test" runat="server"
OnItemDataBound="rep_test_ItemDataBound">
Then in the back end, add a handler, with a FindControl call.
protected void rptBasket_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item ||
e.Item.ItemType == ListItemType.AlternatingItem)
{
Repeater innerRepeater = (Repeater)e.Item.FindControl("rep_hello");
// Now your have your repeater...do what you want with it.
}
}

Change an ASP.NET control's properties in a Repeater control

My question is fairly simple. This is what I have for the aspx page:
<ul>
<asp:Repeater runat="server" ID="linksList" OnItemDataBound="linksList_OnItemDataBound" >
<ItemTemplate>
<li><asp:HyperLink runat="server" ID="link" /></li>
</ItemTemplate>
</asp:Repeater>
</ul>
I'm trying to get a list of hyperlinks from a SQL server into a list. This is what I have in the codebehind:
protected void Page_Load(object sender, EventArgs e)
{
DataSet ds = Utilities.RunSelectQuery("SELECT *");
DataTable dt = ds.Tables[0];
linksList.DataSource = dt;
linksList.DataBind();
}
How do I change the NavigateUrl and Text properties in the asp:HyperLink after data's been bound to the Repeater? I want to do this in the codebehind, I can get it to work if I do it using <%# Eval("URL") %> in the aspx page but that's sort of against what ASP.NET is all about.
Edit: this is the solution that worked for me thanks to womp:
protected void linksList_OnItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
DataRowView row = (DataRowView)e.Item.DataItem;
HyperLink link = (HyperLink)e.Item.FindControl("link");
link.Text = row["description"].ToString();
link.NavigateUrl = row["URL"].ToString();
}
}
Actually, using the Databinder syntax in your templates is a great way to do it, I'm not sure what you mean that it's "against what ASP.Net is all about".
However, if you really want to do it in code, you can do it right in your OnItemDataBound handler (which it looks like you've created). Something like this (read: untested) should do the trick:
void linksList_OnItemDataBound(object Sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item
|| e.Item.ItemType == ListItemType.AlternatingItem) {
DataRow row = e.Item.DataItem as DataRow;
Hyperlink link = e.Item.FindControl("link"));
link.Text = row["URL"];
link.NavigateUrl = row["URL"];
}
}
}
The way to do it is just as you said. Doing it in the code behind adds unnecessary work if you only wish to display the URL. You also would want to put the tags in the HeaderTemplate and FooterTemplate.
<asp:Repeater runat="server" ID="linksList" OnItemDataBound="linksList_OnItemDataBound" >
<HeaderTemplate><ul></HeaderTemplate>
<ItemTemplate>
<li><asp:HyperLink runat="server" ID="link" NavigateUrl='<%# Eval("url") %>' /></li>
</ItemTemplate>
<FooterTemplate></ul></FooterTemplate>
</asp:Repeater>

Resources