I've spent the past few hours searching, and I can't find a solution to my problem. The title is pretty wordy, but I think it describes my situation exactly. See the below code. I've tried adding the SelectedIndexChanged function on the ItemDataBound event of the repeater, but it seems like the postback event causes the page to forget the handler. Same goes for using the Triggers.Add to add an AsyncPostbackTrigger.
The solution which worked was to re-add the EventHandler on postback, but this isn't a workable solution for me. I could write a custom function to loop through my repeater DataSource independent of the actual DataBinding, and then specifically re-bind the EventHandler when applicable, but this seems to be an extremely brute-force approach. Is there no better way of accomplishing my objective?
Front-end:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="smMain" runat="server" />
<div>
<asp:UpdatePanel ID="updTest" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<asp:Repeater ID="rptTest" runat="server" OnItemDataBound="rptTest_ItemDataBound">
<ItemTemplate>
<asp:RadioButtonList ID="rblTest" runat="server" RepeatDirection="Horizontal" ClientIDMode="AutoID" />
</ItemTemplate>
</asp:Repeater>
</ContentTemplate>
</asp:UpdatePanel>
</div>
</form>
</body>
</html>
Back-end:
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
DataTable dt = new DataTable();
dt.Columns.Add("Test");
DataRow dr = dt.NewRow();
dr["Test"] = "FirstRow";
dt.Rows.Add(dr);
dr = dt.NewRow();
dr["Test"] = "SecondRow";
dt.Rows.Add(dr);
rptTest.DataSource = dt;
rptTest.DataBind();
}
else
{
// This works, but it's very, very ugly. Also, I have no way of being able to test for which function I actually want to call!
((RadioButtonList)FindControl(Request.Params["__EVENTTARGET"])).SelectedIndexChanged += testFunction;
}
}
protected void rptTest_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
RadioButtonList rbl = (RadioButtonList)e.Item.FindControl("rblTest");
DataTable dt = new DataTable();
dt.Columns.Add("ButtonName");
dt.Columns.Add("ButtonID");
DataRow dr = dt.NewRow();
dr["ButtonName"] = "Yes";
dr["ButtonID"] = "1";
dt.Rows.Add(dr);
dr = dt.NewRow();
dr["ButtonName"] = "No";
dr["ButtonID"] = "2";
dt.Rows.Add(dr);
rbl.DataTextField = "ButtonName";
rbl.DataValueField = "ButtonID";
rbl.DataSource = dt;
rbl.DataBind();
rbl.AutoPostBack = true;
//This doesn't work. Even though it's set here, it doesn't "remember" the setting on postback
//rbl.SelectedIndexChanged += testFunction;
//This doesn't work either. Again, it doesn't "remember" the setting on postback
//updTest.Triggers.Add(new AsyncPostBackTrigger() { ControlID = rbl.UniqueID });
}
private void testFunction(object sender, EventArgs e)
{
}
}
Found the solution to the problem. Essentially, I need to bind the EventHandler on the ItemCreated event, instead of on the ItemDataBound event. The ItemCreated event is fired for each postback, and not only on the first, so the EventHandler can be re-bound properly.
Front-end:
<asp:Repeater ID="rptTest" runat="server" OnItemCreated="rptTest_ItemCreated" OnItemDataBound="rptTest_ItemDataBound">
Back-end:
protected void rptTest_ItemCreated(object sender, RepeaterItemEventArgs e)
{
RadioButtonList rbl = (RadioButtonList)e.Item.FindControl("rblTest");
rbl.SelectedIndexChanged += testFunction;
}