asp.netserver-side-controls

asp.net web forms best practice to retrieve dynamic server control values


I populate web form with dynamic list of exams from database. I want user to enter examination marks for each exam. There is list of exam titles and textbox near each title.

I create list with repeater control (ViewState is disabled) :

<asp:Repeater ID="rptExams" runat="server" onitemdatabound="rptExams_ItemDataBound" >    
        <ItemTemplate>        
                <tr>
                    <td>                        
                        <asp:Literal runat="server" ID="ltTitle"/>
                    </td>
                    <td>
                        <asp:HiddenField runat="server" ID="hfId"/>
                        <asp:Textbox runat="server" ID="tbMark"/>
                    </td>
                </tr>
        </ItemTemplate>    
    </asp:Repeater>

And bind data to repeater on page_init:

class Exam
{
    public int Id { get; set;}
    public string Title { get; set;}
}
...
// this list is retrieved from database actually 
Exam[] Exams = new Exam[]
{
    new Exam { Id = 1, Title = "Math"},
    new Exam { Id = 2, Title = "History"}                                        
};
...
protected void Page_Init(object sender, EventArgs e)
{
    rptExams.DataSource = Exams;
    rptExams.DataBind();
}

So far so good. Then I have to retrieve data on postback. I have two ways but both of them looks ugly. Idea is to store dynamically created databounded controls on ItemDataBoundEvent in Page_Init stage, and process their values in Page_Load stage. It looks like this:

private Dictionary<HiddenField, TextBox> Id2Mark = new Dictionary<HiddenField, TextBox>();

protected void rptExams_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
    ...
    if (IsPostBack)
    {
        var tbMark = (TextBox)e.Item.FindControl("tbMark");
        var hfId = (HiddenField)e.Item.FindControl("hfId");

        // store dynamically created controls 
        Id2Mark.Add(hfId, tbMark);
    } 
    ...    
}

protected void Page_Load(object sender, EventArgs e)
{
    if (IsPostBack)
    {
        foreach (var pair in Id2Mark)
        {
            int examId = Int32.Parse(pair.Key.Value);
            string mark = pair.Value.Text;
            // PROCESS 
        }
...

I'm completely sure there is a better way to retrieve data from dynamically created controls. Thank you in advance!


Solution

  • Here's how you can do it:

    First, don't rebind the data on postback - it's not necessary. Only bind it on the first call of the page.

    protected void Page_Init(object sender, EventArgs e)
    {
        if (!IsPostBack){
            rptExams.DataSource = Exams;
            rptExams.DataBind();
        }
    }
    

    You won't need the Dictionary neither.

    Then, on a postback, you can get to the bound data as follows:

    protected void Page_Load(object sender, EventArgs e)
    {
        if (IsPostBack)
        {
            foreach (RepeaterItem item in rptExams.Items)
            {
                HiddenField hfId = item.FindControl("hfId") as HiddenField;
                TextBox tbMark = item.FindControl("tbMark") as TextBox;
    
                int examId = Int32.Parse(hfId);
                string mark = tbMark.Text;
                // PROCESS 
            }
        }
    }