Repeater in Repeater - asp.net

I have a repeater inside a repeater. Where the parent repeater is bound to a Datatble which has a column with a Datatable in it.
I would like to bind the child repeater to the datatable column in the parent repeater's datarow
Is this possible? i was thinking i could do this directly in the aspx file like:
DataSource="<%# DataBinder.Eval(Container.DataItem, "Products")%>" but it doesn't seem to work.

In the parent repeater, attach a method to the OnItemDataBound event and in the method, find the nested repeater and data bind it.
Example (.aspx):
<asp:Repeater ID="ParentRepeater" runat="server" OnItemDataBound="ItemBound">
<ItemTemplate>
<!-- Repeated data -->
<asp:Repeater ID="ChildRepeater" runat="server">
<ItemTemplate>
<!-- Nested repeated data -->
</ItemTemplate>
</asp:Repeater>
</ItemTemplate>
</asp:Repeater>
Example (.cs):
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
ParentRepeater.DataSource = ...;
ParentRepeater.DataBind();
}
}
protected void ItemBound(object sender, RepeaterItemEventArgs args)
{
if (args.Item.ItemType == ListItemType.Item || args.Item.ItemType == ListItemType.AlternatingItem)
{
Repeater childRepeater = (Repeater)args.Item.FindControl("ChildRepeater");
childRepeater.DataSource = ...;
childRepeater.DataBind();
}
}

I would add a DataBinding event to the child repeater itself:
<asp:Repeater ID="parentRepeater" runat="server">
<asp:Repeater ID="childRepeater" runat="server"
OnDataBinding="childRepeater_DataBinding" />
</asp:Repeater>
Then just implement it:
protected void childRepeater_DataBinding(object sender, System.EventArgs e)
{
Repeater rep = (Repeater)(sender);
int someIdFromParentDataSource = (int)(Eval("ParentID"));
// Assuming you have a function call `GetSomeData` that will return
// the data you want to bind to your child repeater.
rep.DataSource = GetSomeData(int);
rep.DataBind();
}
I prefer to do it at the control level instead of the ItemDataBound level so that if you ever have to remove controls or items within your templates you don't have to worry about looking for code in the parent controls that use it. It get's all localize witht he control itself. Plus you never have to do a FindControl.
If you want to replace a control in the future you can just delete it and your code will still work since it is all self contained. Using the ItemDataBound would cause your code to still compile but crash or act unexpectedly at runtime because of it's reliance on child controls.

Here is how it's done:
DataSource='<%# ((System.Data.DataRowView)Container.DataItem)[3] %>'
So if you know the column in the parent table that holds the child table/datasource for the nested repeater you can put this directly in the aspx file.

Repeater1 OnItemDataBound event, then FindControl Repeater2. The code-behind will not find the nested Repeater2! You have to use FindControl("Repeater2").
protected void Repeater1_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.DataItem != null)
{
MemberView dataRow = (MemberView)e.Item.DataItem;
var cat = MemberPresenter.getMemberID(dataRow.memID);
Repeater rp2 = (Repeater)e.Item.FindControl("Repeater2");
rp2.DataSource = cat;
rp2.DataBind();
}
}

If I need to do that, I usually do it using the ItemDataBound event of the parent repeater to bind the child repeater. If e is your EventArgs parameter, you'll have access to the child repeater via e.Item.FindControl(), and access to the data via e.Item.DataItem.

Here is an example of how to do this:
Article for nested repeater control

protected void MainRepeater_ItemDataBound(object sender, RepeaterItemEventArgs args)
{
if (args.Item.ItemType == ListItemType.Item || args.Item.ItemType == ListItemType.AlternatingItem)
{
Repeater childRepeater = (Repeater)args.Item.FindControl("ChildRepeater");
DataTable innerTable= ((DataRowView)args.Item.DataItem)["InnerTableColumnName"] as DataTable;
childRepeater.DataSource = tasksDetails;
childRepeater.DataBind();
}
}

Related

How to get the repeater-item in a Checkbox' CheckedChanged-event?

I have a CheckBox inside a Repeater. Like this:
<asp:Repeater ID="rptEvaluationInfo" runat="server">
<ItemTemplate>
<asp:Label runat="server" Id="lblCampCode" Text="<%#Eval("CampCode") %>"></asp:Label>
<asp:CheckBox runat="server" ID="cbCoaching" value="coaching-required" ClientIDMode="AutoID" AutoPostBack="True" OnCheckedChanged="cbCoaching_OnCheckedChanged" />
</ItemTemplate>
</asp:Repeater>
When some one clicks on the checkbox I want to get that entire row in my code behind. So if a CheckedChanged happens I want to get the Text of the Label lblCampCode in code behind.
Is it possible?
I have managed to write this much code.
protected void cbCoaching_OnCheckedChanged(object sender, EventArgs e)
{
CheckBox chk = (CheckBox)sender;
Repeater rpt = (Repeater)chk.Parent.Parent;
string CampCode = "";// here i want to get the value of CampCode in that row
}
So you want to get the RepeaterItem? You do that by casting the NamingContainer of the CheckBox(the sender argument). Then you're almost there, you need FindControl for the label:
protected void cbCoaching_OnCheckedChanged(object sender, EventArgs e)
{
CheckBox chk = (CheckBox)sender;
RepeaterItem item = (RepeaterItem) chk.NamingContainer;
Label lblCampCode = (Label) item.FindControl("lblCampCode");
string CampCode = lblCampCode.Text;// here i want to get the value of CampCode in that row
}
This has the big advantage over Parent.Parent-approaches that it works even if you add other container controls like Panel or Table.
By the way, this works the similar way for any databound web-control in ASP.NET (like GridView etc).

Handling the checkedchanged event of inner repeater Checkbox control in asp.net nested repeaters

I have nested repeaters on my aspx page.In the outer repeater I am displaying a list of products and in the inner repeater I am displaying a list of additional options associated with each product.The inner repeater contains a checkbox,textbox,label and other stuff.I would like to find the controls inside the outer repeater when a user selects a checkbox in the inner repeater.In order to handle this I am using the following code.
<asp:Repeater ID="OuterRepeater" runat="server"
onitemdatabound="OuterRepeater_ItemDataBound" >
<ItemTemplate>
<asp:Label ID="CodeLabel" runat="server" Text='<%# Eval("Code") %>'></asp:Label>
<asp:Repeater ID="InnerRepeater" runat="server" OnItemCreated="InnerRepeater_ItemCreated">
<ItemTemplate>
<asp:CheckBox ID="CheckBox1" runat="server" AutoPostBack="true"/>
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
......
.......
</ItemTemplate>
</asp:Repeater>
......
......
</ItemTemplate>
</asp:Repeater>
protected void InnerRepeater_ItemCreated(object sender, RepeaterItemEventArgs e)
{
RepeaterItem ri = (RepeaterItem)e.Item;
if (ri.ItemType == ListItemType.Item || ri.ItemType == ListItemType.AlternatingItem
)
{
CheckBox cb = ri.FindControl("CheckBox1") as CheckBox;
cb.CheckedChanged += new EventHandler(CheckBox1_CheckedChanged);
}
}
private void CheckBox1_CheckedChanged(object sender, EventArgs e)
{
CheckBox cb = (CheckBox)sender;
if (cb.Checked)
{
//do something
}
else
{
//do something
}
}
But the checkedChanged event of the checkbox is not firing for some reason.Also I am not sure how to access the textbox of the outer repeater in the checked changed event of the innter repeater checkbox control.
Could someone please help me with this?
Thanks
It does not fire the CheckedChanged event, since you have declared the event handler as private, You have to make it Protected or Public
Protected void CheckBox1_CheckedChanged(object sender, EventArgs e)
You can access the Textbox control like..
private void CheckBox1_CheckedChanged(object sender, EventArgs e)
{
CheckBox checkBox = (CheckBox)sender;
Textbox textbox1 = (TextBox)checkBox.Parent.FindControl("TextBox1");
String textboxText = textbox1.Text;
}
It doesn't look like you defined an event handler in your markup.
<asp:CheckBox ID="CheckBox1" runat="server" AutoPostBack="true" OnCheckedChanged="CheckBox1_CheckedChanged" />
Muhammad Akhtar's answer helped me a lot today!
I just needed to set a specific ID to my dynamic generated checkboxes inside my reapeater to recover the origin of the event, and do the rest of the processing, and it worked perfectly.
chkAtivo.ID = DataBinder.Eval(e.Item.DataItem, "id").ToString();
Reovered just as the sample.
Cant vote up yet, but thank you.

Why won't my LinkButton inside a GridView raise its OnClick event?

I have a LinkButton inside a GridView (via an TemplateField). No matter what I try, the LinkButton will not invoke its event handler. I have tried both:
A traditional event handler ("OnClick")
A OnRowCommand event handler at the GridView level.
In both cases, I've debugged and it doesn't even catch the event handler.
If I move the LinkButton out on the page (so it's not in the GridView), it works fine, so I know the syntax is right.
Here is the "traditional" method:
<asp:TemplateField>
<ItemTemplate>
<asp:LinkButton Text="Cancel" ID="DeleteButton" CausesValidation="false" OnClick="CancelThis" runat="server" />
</ItemTemplate>
<asp:TemplateField>
What's interesting is if I remove the "CancelThis" method from the code behind, it throws an error. So I know it's aware of its event handler, because it looks for it when it compiles.
Here is the RowCommand method:
<asp:TemplateField>
<ItemTemplate>
<asp:LinkButton Text="Cancel" ID="DeleteButton" CausesValidation="false" CommandName="CancelThis" runat="server" />
</ItemTemplate>
<asp:TemplateField>
In this case, the GridView has:
OnRowCommand="GridView_RowCommand"
It postsback, but never hints at raising the event.
Any idea what I'm missing here?
How are you binding your GridView? Are you using a datasource control? If you are binding manually during Page_Load, it's possible that since the grid is binding every round trip, the event handler isn't catching properly. If this is the case, you may want to try something like:
protected void Page_Load(object sender, EventArgs e)
{
if(!Page.IsPostBack)
{
//do binding
}
}
Can you post sample binding code to go with your markup?
If you really want to force the issue, you could hook into the RowDataBound event on the Grid, find the button manually and add the handler in the code behind. Something like:
markup snippet:
<asp:GridView ID="gvTest" runat="server" OnRowDataBound="gvTest_RowDataBound" />
code behind:
protected void gvTest_RowDataBound(object sender, GridViewRowEventArgs e)
{
if(e.Row.RowType == DataControlRowType.DataRow)
{
//find button in this row
LinkButton button = e.Row.FindControl("DeleteButton") as button;
if(button != null)
{
button.Click += new EventHandler("DeleteButton_Click");
}
}
}
protected void DeleteButton_Click(object sender, EventArgs e)
{
LinkButton button = (LinkButton)sender;
// do as needed based on button.
}
I'm not sure what the purpose of the button is, but assuming it is a row delete button, you may not want to take this approach as in the event handler, you don't have direct access to the row in question, like you would using the RowCommand event.
Is there a reason you're using the Template field? Vs say a ButtonField? If you use a ButtonField, then you can hook into the RowCommand event.
markup snippet:
<asp:GridView ID="gvTest" runat="server" OnRowCommand="gvTest_RowCommand">
<columns>
<asp:buttonfield buttontype="Link" commandname="Delete" text="Delete"/>
....
</columns>
</asp:GridView>
code behind:
protected void gvTest_RowCommand(object sender, GridViewCommandEventArgs e)
{
if(e.CommandName == "Delete")
{
//take action as needed on this row, for example
int rowIndex = Convert.ToInt32(e.CommandArgument);
GridViewRow currentRow = (sender as GridView).Rows[rowIndex];
//do something against the row...
}
}
You might want to consult MSDN docs on some of these topics:
RowCommandEvent
ButtonField class
EDIT:
To answer your question on the ButtonField - yes I don't see why you couldn't still deal with a buttonfield. Here's a snippet to find the buttonfield during row data bound and hide it (untested but I think would work...)
protected void gvTest_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
//let's assume your buttonfield is in column 1
// (you'd know this based on your markup...)
DataControlFieldCell cell = e.Row.Cells[1] as DataControlFieldCell;
if(cell != null)
{
ButtonField field = cell.ContainingField as ButtonField;
//based on your criteria, show or hide the button
field.Visible = false;
//or
field.Visible = true;
}
}
}
Is viewstate turned on on your GridView? This has caught me out numerous times.
<button onclick="window.open('<%#Eval("ReportLinks")%>', '_blank');" title='<%#Eval("ReportLinks")%>'> Link</button>

Implementing a functional link in a Repeater control

I am implementing a Repeater in my web application to display data. I want to add functional action links in a column similar to the built-in functionality in a GridView. Can anybody give me the steps required? I assume I will add a LinkButton control to each row, somehow set the OnClick event handler to point to the same method, and somehow pass in the unique identifier on the row as a parameter.
Thanks!
I'm guessing this is what you want.
<asp:Repeater ID="rpt" runat="server">
<ItemTemplate>
<asp:LinkButton ID="lbtn" runat="server" OnCommand="lbtn_Command"
CommandArgument='<%# DataBinder.Eval(Container.DataItem, "KeyIDColumn") %>' ></asp:LinkButton>
</ItemTemplate>
</asp:Repeater>
Then in your code behind
protected void lbtn_Command(object sender, CommandEventArgs e)
{
int id = Convert.ToInt32(e.CommandArgument);
}
Use LinkButtons. That way, you can handle the OnClick event in the code behind.
First you would set the onclick of the linkbutton in markup. You'll then want to implement the ItemDataBound event for the repeater.
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
SomeObject obj = e.Item.DataItem as SomeObject; // w/e type of item you are bound to
var linkButton = e.Item.FindControl("linkButtonId") as LinkButton;
if(linkButton != null)
{
//either set a custom attribute or maybe append it on to the linkButton's ID
linkButton.Attributes["someUniqueId"] = obj.SomeID;
}
}
Then in the click event
void lb_Click(object sender, EventArgs e)
{
LinkButton lb = sender as LinkButton;
if (lb != null)
{
// obviously do some checking to ensure the attribute isn't null
// and make it the correct datatype.
DoSomething(lb.Attributes["someUniqueId"]);
}
}

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