Items are looping all items in Repeater's ItemDataBound event - c#

I have a normal Repeater Control in my aspx page
<asp:Repeater ID="rpt1" runat="server" OnItemDataBound="rpt1_ItemDataBound">
<ItemTemplate>
<asp:CheckBox ID="chks" runat="server" />
<asp:TextBox ID="txtName" runat="server" CssClass="form-control" Text='<%# DataBinder.Eval(Container,"DataItem.Name").ToString()%>'></asp:TextBox><asp:Label ID="lblValue" runat="server" Visible="false" Text='<%# DataBinder.Eval(Container,"DataItem.Id").ToString() %>'></asp:Label>
</ItemTemplate>
</asp:Repeater>
On the button click I'm binding data to the Repeater as
rpt1.DataSource = GetData();
rpt1.DataBind();
After binding the ItemDataBound event is called. In that I'm looping through the repeater items for some manipulations
protected void rpt1_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
foreach (RepeaterItem item in rpt1.Items)
{
if (item.ItemType == ListItemType.Item || item.ItemType == ListItemType.AlternatingItem)
{
string val = ((Label)item.FindControl("lblValue")).Text;
// Some Stuff
}
}
}
The problem is that the loop is getting started from first every time.
For Ex if my data is as 1 2 3 so on.....
It is iterarting as
1
1 2
1 2 3
How can I make it as
1
2
3
What am I doing wrong

ItemDataBound is already called for every item in the repeater, so you don't need a loop there.
protected void rpt1_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
string val = ((Label)e.Item.FindControl("lblValue")).Text;
// Some Stuff
}
}
Side-Note: that applies to all Data-Bound Web Server Controls.

Related

Display category once in repeater

I have a repeater wanting to display Categories and products. Category should appear once and products would appear the number of products i have. Below is my markup
<asp:Repeater ID="rpt1" runat="server" OnItemDataBound="rpt1_ItemDataBound">
<ItemTemplate>
<asp:Label ID="lblCategory" runat="server"></asp:Label>
<asp:Label ID="lblProductName" runat="server"></asp:Label>
</ItemTemplate>
</asp:Repeater>
I bind the products at page load
if (!Page.IsPostBack)
{
LoadData();
}
My codebehind
protected void rpt1_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
Product p = (Product)e.Item.DataItem;
Label lblCategory = e.Item.FindControl("lblCategory") as Label;
Label lblProductName = e.Item.FindControl("lblProductName") as Label;
lblProductName.Text = p.ProductName;
lblCategory.Text = p.Category.CategoryName;
}
}
Everything works but my category text is repeated more than once (its shown the number of products i have). How could i display the category just once?
Edit
Cat 20 is Stationery
Cat 30 is Computer Items
Cat 40 is Toiletry
**Id CatId ProductName**
1 20 Pencil
1 20 Pen
1 30 Compact Disc
1 30 USB
1 30 Hard drive
1 40 Toothpaste
1 40 Toothbrush
I get my data in an
Iqueryable<Product> LoadData = myContext.GetProducts();
I think using nested repeater would be better in that case. I mean first repeater for Categories and the nested repeater for Products of it's category. See: Nested repeater.
<asp:Repeater runat="server" id="Categories">
<ItemTemplate>
Category: <%# Eval("CategoryName") %>
Products:
<asp:Repeater runat="server" DataSource='<%# Eval("Products") %>'>
<ItemTemplate><%# Eval("ProductName") %></ItemTemplate>
</asp:Repeater>
</ItemTemplate>
</asp:Repeater>
But to do this you need to work on data model a bit, your model should be like this:
public class Category
{
public string CategoryName {get; set;}
public IEnumerable<Product> Products {get; set;}
}
public class Product
{
public string ProductName {get; set;}
}
Or dirty-quick solution is that by comparing category name to previous row for each repeater item. If category name is changed then display new category name, otherwise set empty:
protected void rpt1_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
Product p = (Product)e.Item.DataItem;
Label lblCategory = e.Item.FindControl("lblCategory") as Label;
Label lblProductName = e.Item.FindControl("lblProductName") as Label;
lblProductName.Text = p.ProductName;
if(e.Item.ItemIndex > 0)
{
RepeaterItem previousRepeaterItem = rpt1.Items[e.Item.ItemIndex - 1];
var previousCategoryName = (previousRepeaterItem.FindControl("lblCategory") as Label).Text;
if(previousCategoryName != p.Category.CategoryName)
{
lblCategory.Text = p.Category.CategoryName;
}
}
}
}
I am not sure about the complexity of the product data that you wish to display. Yet I would like to suggest you using the nested Repeaters, one repeater will have category name and the second would have the products. On Page_Load, you should fetch all distinct categories and bind the first repeater And on ItemDataBound of first repeater you must fetch products relevant to the category and bind the nested repeater.
e.g:
<asp:Repeater ID="rpt1" runat="server" OnItemDataBound="rpt1_ItemDataBound">
<ItemTemplate>
<asp:Label ID="lblCategory" runat="server" Text='<%# Eval("Category") %>'></asp:Label>
<asp:Repeater ID="rpt2" runat="server">
<ItemTemplate>
<asp:Label ID="lblProductName" runat="server" Text='<%# Eval("ProductName")%>'></asp:Label>
</ItemTemplate>
</asp:Repeater>
</ItemTemplate>
</asp:Repeater>
Page Load:
protected void Page_Load(object s, EventArgs e)
{
// Fetch All the Categories, Distinct Elements
DataTable dt = new DataTable();
dt.Columns.Add("Category");
dt.Rows.Add("Sanatizers");
dt.Rows.Add("Soaps");
rpt1.DataSource = dt;
rpt1.DataBind();
}
Item Data Bound:
protected void rpt1_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
Label lblCategory = (Label)e.Item.FindControl("lblCategory");
Repeater rpt2 = (Repeater)e.Item.FindControl("rpt2");
if (lblCategory != null)
{
// Fetch products by category
var dt = new DataTable();
dt.Columns.Add("ProductName");
dt.Rows.Add("Dettol");
dt.Rows.Add("Safeguard");
dt.Rows.Add("Fair and Lovely");
rpt2.DataSource = dt;
rpt2.DataBind();
}
}
}
PS: The code is not tested, it might need some love.

Error in getting Nullreferenceexception even though there is text assigned to the label

I have been getting the NullrefernceException on my aspx.cs page even though I already assigned a text for the label in my aspx page. At first i thought it could be the session but i log in and try i still get the same error. I have checked my database and the spelling and there is nothing wrong
My aspx.cs code:
protected void Page_Load(object sender, EventArgs e)
{
Label Lefthowmanylabel =(Label)DataList1.FindControl("Lefthowmanylabel");
Label quantitylabel = (Label)DataList1.FindControl("quantitylabel");
if (int.Parse(quantitylabel.Text) < 11)
{
Lefthowmanylabel.Visible = true;
}
else
{
Lefthowmanylabel.Visible = false;
}
}
My datalist item in aspx page:
<asp:Label ID="Lefthowmanylabel" runat="server" Text="Only 10 Left!! While stock last!" Visible="False"/>
<asp:Label ID="quantitylabel" runat="server" Text='<%# Eval("Quantity") %>' Visible="False" />
</td>
If you want to access access controls inside DataList and manipulate them, you want to use ItemDataBound.
For example,
<asp:DataList ... OnItemDataBound="Item_Bound" runat="server">
</asp:DataList>
void Item_Bound(Object sender, DataListItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item ||
e.Item.ItemType == ListItemType.AlternatingItem)
{
Label lefthowmanylabel =(Label)e.Item.FindControl("Lefthowmanylabel");
Label quantitylabel = (Label)e.Item.FindControl("quantitylabel");
if (int.Parse(quantitylabel.Text) < 11)
{
lefthowmanylabel.Visible = true;
}
else
{
lefthowmanylabel.Visible = false;
}
}
}

Nested repeater will not display bound information from list

I am trying to get a page to display information in a row layout using repeaters. I have one working that allows me to dynamically create hyperlinks, however i cant get my nested repeater to work to display the date the file was created. Is it possible to use repeaters to dynamically display multiple variables from lists as i'm trying to do below?
.aspx
<asp:Repeater id="repLinks" runat="server">
<ItemTemplate>
<tr><td>
<asp:HyperLink runat="server" NavigateUrl='<%# Container.DataItem.ToString() %>' Text="<%# Container.DataItem.ToString().Split('\\').Last() %>" />
<td>
<asp:Repeater ID="Repeater2" runat="server" OnItemDataBound="Repeater2_ItemDataBound" >
<ItemTemplate>
<%# Container.DataItem.ToString()%>
</ItemTemplate>
</asp:Repeater>
</td>
<td>
Submitted By <!--add repeater-->
</td>
<td>
Mark as Billed <!--add repeater-->
</td>
</td></tr>
</ItemTemplate>
</asp:Repeater>
.aspx.cs
public List<string> CD = new List<string>();
protected void Page_Load(object sender, EventArgs e)
{
//Welcomes User
string Uname = Environment.UserName;
UserName.Font.Size = 17;
UserName.Text = "Welcome: " + Uname;
//gives path and constructs lists for directory paths and file links
string root = "C:\\Users\\James\\Documents\\Visual Studio 2015\\WebSites";
List<string> lLinks = new List<string>();
//adds files to list
foreach (var path in Directory.GetDirectories(#root))
{
foreach (var path2 in Directory.GetFiles(path))
{
lLinks.Add(path2);
CD.Add(File.GetCreationTime(path2).Date.ToString("yyyy-mm-dd"));
}
}
//Define your list contents here
repLinks.DataSource = lLinks;
repLinks.DataBind();
}
protected void Repeater2_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
Repeater Repeater2 = (Repeater)(e.Item.FindControl("Repeater2"));
Repeater2.DataSource = CD;
Repeater2.DataBind();
}
}
The issue with your code is that you are binding the nested repeater control (Repeater2) in the ItemDataBound event of Repeater2 repeater itself which will never get fired because ItemDataBound event is fired for each item in collection when it is bounded to the repeater control.
You should write the logic in ItemDataBound event of your parent repeater like this:-
<asp:Repeater id="repLinks" runat="server" OnItemDataBound="Repeater1_ItemDataBound">
Then, write the logic in this event handler:-
protected void Repeater1_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item ||
e.Item.ItemType == ListItemType.AlternatingItem)
{
Repeater Repeater2 = (Repeater)(e.Item.FindControl("Repeater2"));
Repeater2.DataSource = CD;
Repeater2.DataBind();
}
}
Also, In the Page_Load event you should bind the Parent Repeater Repeater1 on just the initial page load so wrap it inside !IsPostBack and populate your datasource lLinks & CD from a separate method intead of doing it in Page_Load event.

Passing the current Item to a function

I have a Repeater:
<asp:Repeater runat="server" ID="RepeaterCategorie">
<ItemTemplate>
<%#((isBlocked()) ? "true" : "false") %>
</ItemTemplate>
</asp:Repeater>
where I call a function on the .cs. I'd like to pass the current item (I mean, the current item iterate in the list of the datasource) to that function. How can I do it without passing the reference through the isBlocked function?
HTML
<asp:Repeater runat="server" ID="RepeaterCategorie"
OnItemDataBound="RepeaterCategorie_ItemDataBound">
<ItemTemplate>
<asp:Label runat="server" Id="lblBool"></asp:Label>
</ItemTemplate>
</asp:Repeater>
CS
protected void RepeaterCategorie_ItemDataBound(
object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item ||
e.Item.ItemType == ListItemType.AlternatingItem)
{
var lblBool = (Label)e.Item.FindControl("lblBool");
lblBool.Text = isBlocked(sender, e) ? "true" : "false";
}
}

Can't find control within asp.net repeater?

I have the following repeater below and I am trying to find lblA in code behind and it fails. Below the markup are the attempts I have made:
<asp:Repeater ID="rptDetails" runat="server">
<HeaderTemplate>
<table>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td><strong>A:</strong></td>
<td><asp:Label ID="lblA" runat="server"></asp:Label>
</td>
</tr>
</ItemTemplate>
</asp:Repeater>
</table>
First I tried,
Label lblA = (Label)rptDetails.FindControl("lblA");
but lblA was null
Then I tried,
Label lblA = (Label)rptDetails.Items[0].FindControl("lblA");
but Items was 0 even though m repeater contains 1 itemtemplate
You need to set the attribute OnItemDataBound="myFunction"
And then in your code do the following
void myFunction(object sender, RepeaterItemEventArgs e)
{
Label lblA = (Label)e.Item.FindControl("lblA");
}
Incidentally you can use this exact same approach for nested repeaters. IE:
<asp:Repeater ID="outerRepeater" runat="server" OnItemDataBound="outerFunction">
<ItemTemplate>
<asp:Repeater ID="innerRepeater" runat="server" OnItemDataBound="innerFunction">
<ItemTemplate><asp:Label ID="myLabel" runat="server" /></ItemTemplate>
</asp:Repeater>
</ItemTemplate>
</asp:Repeater>
And then in your code:
void outerFunction(object sender, RepeaterItemEventArgs e)
{
Repeater innerRepeater = (Repeater)e.Item.FindControl("innerRepeater");
innerRepeater.DataSource = ... // Some data source
innerRepeater.DataBind();
}
void innerFunction(object sender, RepeaterItemEventArgs e)
{
Label myLabel = (Label)e.Item.FindControl("myLabel");
}
All too often I see people manually binding items on an inner repeater and they don't realize how difficult they're making things for themselves.
I just had the same problem.
We are missing the item type while looping in the items. The very first item in the repeater is the header, and header does not have the asp elements we are looking for.
Try this:
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{Label lblA = (Label)rptDetails.Items[0].FindControl("lblA");}
Code for VB.net
Protected Sub rptDetails_ItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.RepeaterItemEventArgs) Handles rptDetails.ItemDataBound
If e.Item.ItemType = ListItemType.AlternatingItem Or e.Item.ItemType = ListItemType.Item Then
Dim lblA As Label = CType(e.Item.FindControl("lblA"), Label)
lblA.Text = "Found it!"
End If
End Sub
Investigate the Repeater.ItemDataBound Event.
You should bind first.
for example)
rptDetails.DataSource = dataSet.Tables["Order"];
rptDetails.DataBind();

Categories