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

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>

Related

Difficulty in displaying data using repeater

I am trying to display shopping categories with its sub categories and sub-sub categories using repeater.. Data is binding but it is not being displayed.. Can anyone help why?
here's my code:
.aspx file
<asp:Repeater ID="CategoryRepeater" runat="server" OnItemDataBound="CategoryRepeater_OnItemDataBound">
<ItemTemplate>
<a href='Clothing.aspx?CategoryId=<%#Eval("CategoryId") %>'<%#Eval("CategoryName") %>></a><br />
<asp:Repeater ID="SubCategoryRepeater" runat="server" OnItemDataBound="SubCategoryRepeater_OnItemDataBound">
<ItemTemplate>
<a href='Clothing.aspx?CategoryId=<%#Eval("CategoryId") %>&SubCategoryId=<%#Eval("SubCategoryId") %>'<%#Eval("SubCategoryName") %>></a><br />
<asp:Repeater ID="SubSubCategoryRepeater" runat="server">
<ItemTemplate>
<a href='Clothing.aspx?CategoryId=<%#Eval("CategoryId") %>&SubCategoryId=<%#Eval("SubCategoryId") %>&SubSubCategoryId=<%#Eval("SubSubCategoryId") %>'<%#Eval("SubSubCategoryName") %>></a><br />
</ItemTemplate>
</asp:Repeater>
</ItemTemplate>
</asp:Repeater>
</ItemTemplate>
</asp:Repeater>
C# Code:
protected void CategoryRepeater_OnItemDataBound(object sender, RepeaterItemEventArgs e)
{
if ((e.Item.ItemType == ListItemType.Item)||(e.Item.ItemType == ListItemType.AlternatingItem))
{
DataRowView dataItem = e.Item.DataItem as DataRowView;
int categoryId = Convert.ToInt32(dataItem["CategoryId"]);
Repeater rp = (Repeater)e.Item.FindControl("SubCategoryRepeater");
ds = us.SelectSubCategories(categoryId);
rp.DataSource = ds;
rp.DataBind();
}
}
protected void SubCategoryRepeater_OnItemDataBound(object sender, RepeaterItemEventArgs e)
{
if ((e.Item.ItemType == ListItemType.Item)||(e.Item.ItemType == ListItemType.AlternatingItem))
{
DataRowView dataItem = e.Item.DataItem as DataRowView;
int SubCategoryId = Convert.ToInt32(dataItem["SubCategoryId"]);
Repeater rp1 = (Repeater)e.Item.FindControl("SubSubCategoryRepeater");
ds1 = us.SelectSubSubCategories(SubCategoryId);
rp1.DataSource = ds1;
rp1.DataBind();
}
}
Check your source code to make sure nothing is being output to the page. I think you just have the category name being rendered inside the anchor tag.
Here is the same code with the evals simplified to see what is going on
<a href='Clothing.aspx?CategoryId={catid}'{name}></a>
Should be:
<a href='Clothing.aspx?CategoryId={catid}'>{name}</a>
or
<a href='Clothing.aspx?CategoryId=<%#Eval("CategoryId") %>'><%#Eval("CategoryName") %></a>
Same mistake was done in all three locations.
I think everything is correct from the code, but your output is wrong.
You are doing this:
<a href='Clothing.aspx?CategoryId=<%#Eval("CategoryId") %>&SubCategoryId=<%#Eval("SubCategoryId") %>'<%#Eval("SubCategoryName") %>></a><br />
But it needs to be
<a href='Clothing.aspx?CategoryId=<%#Eval("CategoryId") %>&SubCategoryId=<%#Eval("SubCategoryId") %>'><%#Eval("SubCategoryName") %></a><br />
Noticed I moved the '>' back behind <%# Eval("SubCategoryName")%>

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

Using Nested Repeaters With Stored Procedures

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>

Using event of control under datalist

I have a datalist control which some controls(ex: button) are in it. I want to write some code into click event of button which is in the datalist control. But in the code behind page I can't see the name of controls into datalist. How can I solve this problem?
Attach your event to the controls in the OnItemCreated event of the datalist.
EDITED TO ADD SAMPLE
private void DataList_ItemCreated(object sender,
System.Web.UI.WebControls.DataListItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
Button btn = (Button)e.Item.FindControl("btnWhatever");
if (btn != null) btn.Click += new EventHandler(SomHandler);
}
}
If you don't want to add a handler to all the child events, you could instead add your code to the OnItemCommand.
<asp:DataList id="DataList1" runat="server">
<ItemTemplate>
<asp:Button ID="btnDoSomething" Runat=server CommandName="DoSomething"
CommandArgument="<%# DataBinder.Eval(Container.DataItem, "SomeID")
%>"></asp:LinkButton>
</ItemTemplate>
</asp:DataList>
protected void DataList1_ItemCommand(
object source, DataListCommandEventArgs e)
{
if (e.CommandName == "DoSomething")
{
//Do stuff
}
}

Resources