Click here to Skip to main content
15,880,392 members
Articles / Web Development / ASP.NET

Accessing data from dynamically created controls, using ASP.NET 2.0 callback

Rate me:
Please Sign up or sign in to vote.
4.08/5 (5 votes)
24 Feb 2006CPOL3 min read 61K   723   38   2
Storing and retreiving data input from dynamically created controls, without the need to recreate the controls after postback.

Sample Image

Introduction

While developing with ASP.NET 2.0, I ran into a situation where I needed to create controls dynamically. As usual, I started looking for best practice methods by searching the websites and blogs I often turn to. Every example I found talked about the need to recreate the dynamically created controls on postback in order to retrieve the data the user had input or altered. This makes sense: after all, without the controls, the viewstate data for the controls has become orphan data. What if you no longer have a need for the controls that were previously created prior to the postback? Does it really make sense to have to recreate them just to retrieve what is already there? I didn’t think it did, so I started looking for other alternatives. What I found had been there already, just waiting to be used, and just like the code I like to write, it was clean and simple.

Problem

Now that I have setup the problem, let's look at it a little closer. Say, I need to query a database to determine how many TextBoxes need to be dynamically created for a web form that will ask questions that the user needs to answer. I may not be sure how many questions need to be displayed until I have gathered other data from the user. I can then query the database to see how many TextBoxes need to be created, and create each TextBox to display on my web form.

Using the code

The code below will create one TextBox per line, assign an ID to each TextBox, and sets attributes to run a JavaScript (“client side”) function called “processText” when the user leaves the TextBox causing the “OnFocusOut” event to fire.

C#
// This is the data returned from a DataSet.
DataSet DS = new DataSet();
DS = Run the code to query the database.

Session["TextBoxCount"] = DataSet["TextBoxNumber"].ToString();

// This section creates the controls.
for (int a = 0; a < int.Parse(Session["TextBoxCount"].ToString()); a++)
{
   TableRow tr = new TableRow();
   TableCell tc = new TableCell();
   TextBox tb = new TextBox();

   tb.Attributes.Add("runat", "Server");
   tb.Attributes.Add("OnFocusOut", "processText(" + a + ")");
   tb.EnableViewState = false;
   tb.MaxLength = 128;
   tb.ID = "TextBox" + a;

   tc.Controls.Add(tb);
   tr.Cells.Add(tc);
   table.Rows.Add(tr);
}

As stated above, the solution is clean and simple. We all have heard all the craze about AJAX, right? Well, before Jesse James Garrett coined the phrase AJAX, XMLHttpRequest and XMLHttpResponse were available to programmers and web developers coding for IE 5.0. ASP.NET 2.0 includes a callback function similar to what C and C++ developers would be accustomed to using in applications when needing to access functions in a remote API. This callback method in ASP.NET 2.0 allows you to basically do a compressed postback without the need to reload the page contents. As far as I know, I am the only one that refers to the callback method as a compressed postback, and I do that because it uses the same base classes, and if you ever step through your callback method, you will see that the page does indeed postback.

So, the first thing you will need to do is make sure that your page implements ICallbackEventHandler, in your codebehind.

C#
//Example:
public partial class index_aspx : System.Web.UI.Page, 
                                  ICallbackEventHandler

Now, in Page_Load, we need to register our client callback.

C#
//Example:
ClientScriptManager cm = Page.ClientScript;
String cbRef = cm.GetCallbackEventReference(this, 
               "arg", "ReceiveServerData", "context");
String callbackscript = "function callserver(arg," + 
                        "context) {" + cbRef + "}";
cm.RegisterClientScriptBlock(this.GetType(), 
        "CallServer", callbackscript, true);

Next, implement RaiseCallbackEvent, which is the server-side function that handles the client-side call.

C#
//Example:
public void RaiseCallbackEvent(String eventArgument)
{
   int iTyped = int.Parse(eventArgument.Substring(0, 1).ToString());

   if (iTyped != 0) //Process Text Fields
   {
       int Txtid = int.Parse(eventArgument.Substring(1, 1).ToString());

       string TxtData = eventArgument.Substring(2);

       int fields = int.Parse(Session["TextBoxCount "].ToString());
       string[] strTArray = new string[fields];

       if (Session["TextDataArray"].ToString() != "")
       {
          strTArray = (string[])Session["TextDataArray "];
       }

       strTArray[Txtid] = TxtData;
       Session["TextDataArray "] = strTArray;
       this.sGetData = "Done";
   }
}

In the above code snippet, TextDataArray is a session variable that stores data from each TextBox. StrTArray is an array that we populate each time we make a callback to the RaiseCallbackEvent. Once we return to the client side, StrTArray is destroyed and the array is stored as an object in Session["TextDataArray"].

We also will need to add the method that returns the data to the client side.

C#
public String GetCallbackResult()
{
   return this.sGetData;
}

The Client Side

The client side script is very simple. When the “GetCallbackResult” passes the results back from the server side, it is sent to the “ReceiveServerData” function where you process the data in any manner required by your application. In this example, we are simply passing the result into an alert box.

JavaScript
function processText(n)
{
   TBox = document.getElementById("TextBox" +n);
   var data = document.all[TBox].value;
   callserver("1"+n+data);
}

function ReceiveServerData(arg, context)
{
   alert(arg);
}

The Entire Code

All we are doing here is passing the data input from the user back to the server, creating a one dimensional array, and storing the array in a session variable to be used whenever we need it.

Code Behind

C#
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;



public partial class _Default : System.Web.UI.Page, ICallbackEventHandler
{
    string sGetData = "";

    protected void Page_Load(object sender, EventArgs e)
    {
        ClientScriptManager cm = Page.ClientScript;
        String cbRef = cm.GetCallbackEventReference(this, 
                       "arg", "ReceiveServerData", "context");

        String callbackscript = "function callserver(arg," + 
                                "context) {" + cbRef + "}";
        cm.RegisterClientScriptBlock(this.GetType(), 
                "CallServer", callbackscript, true);

      
    }

    public void RaiseCallbackEvent(String eventArgument)
    {
        int iTyped = 
          int.Parse(eventArgument.Substring(0, 1).ToString());

        if (iTyped != 0) Process Text Fields
        {
            int Txtid = 
              int.Parse(eventArgument.Substring(1, 1).ToString());
            string TxtData = eventArgument.Substring(2);

            int fields = 
              int.Parse(Session["TextBoxCount"].ToString());
            string[] strTArray = new string[fields];

            if (Session["TextDataArray"].ToString() != "")
            {
                strTArray = (string[])Session["TextDataArray"];
            }

            strTArray[Txtid] = TxtData;
            Session["TextDataArray"] = strTArray;
            this.sGetData = "Done";
        }
    }

    public String GetCallbackResult()
    {
        return this.sGetData;
    }
   
    protected void Button1_Click(object sender, EventArgs e)
    {
        Session["TextBoxCount"] = "3";

        // This section creates the controls.
        for (int a = 0; a < 
             int.Parse(Session["TextBoxCount"].ToString()); a++)
        {
            TableRow tr = new TableRow();
            TableCell tc = new TableCell();
            TextBox tb = new TextBox();

            tb.Attributes.Add("runat", "Server");
            tb.Attributes.Add("OnFocusOut", 
                              "processText(" + a + ")");
            tb.EnableViewState = false;
            tb.MaxLength = 128;
            tb.ID = "TextBox" + a;

            tc.Controls.Add(tb);
            tr.Cells.Add(tc);
            ctrlTable.Rows.Add(tr);
        }
    }
    protected void Button2_Click(object sender, EventArgs e)
    {
        int fields = int.Parse(Session["TextBoxCount"].ToString());
        string[] strTArray = new string[fields];

        if (Session["TextDataArray"].ToString() != "")
        {
            strTArray = (string[])Session["TextDataArray"];
        }

        for (int a = 0; a < 
             int.Parse(Session["TextBoxCount"].ToString()); a++)
        {
            if (sGetData != "")
            {
                this.sGetData = sGetData + "~" + strTArray[a].ToString();
            }
            else
            {
                this.sGetData = strTArray[a].ToString();
            }
        }
    }
}

Client Side

ASP.NET
<%@ Page Language="C#" AutoEventWireup="true" 
         CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-W3CDTD XHTML 1.0 TransitionalEN" 
    "http:www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http:www.w3.org/1999/xhtml" >
<head runat="server">
   <title>Dynamic TextBox Page</title>
</head>
<body>
   <form id="form1" runat="server">
    <asp:Table ID="ctrlTable" 
               runat="server"></asp:Table>
    <br/>
    <asp:Button ID="Button1" runat="server" 
         OnClick="Button1_Click" 
         Text="Create TextBoxes" />
    <asp:Button ID="Button2" runat="server" 
         Text="Postback and get data" 
         OnClick="Button2_Click" />
   </form>
</body>
</html>

<script type="text/javascript">
function processText(n)
{
  TBox = document.getElementById("TextBox" + n);
  var data = TBox.value;
  callserver("1"+n+data);
}

function ReceiveServerData(arg, context)
{
  alert(arg);
}
</script>

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
United States United States
Possess over 17 years of experience and expertise in the IT industry. Possess in-depth knowledge and experience in the areas of database development, modeling, implementation, wireless integration, and migration, extensive web development skills, and several years of experience providing consulting and training services. Extensive work experience on several integration project for Dell Corporation, Fujitsu, Scholle, Sperry Marine, Vought Aircraft to name a few. Complete understanding of the importance of meeting timelines and budgetary restraints on a per project basis.

As a key member of Brady Systems Integration, created solutions that automated data collection from manufacturing and warehouse thru wireless devices like Symbol, Intermec, and HHP and integrated that data and transactions into the clients back-end business systems. Possess experience integrating into Baan, SAP, JD Edwards, and Great Plaines ERP Systems.

Technical skills include VS.net, Visual Basic, VB.net, C#, ASP.net, J# Palm/OS, Java, Websphere, Lotus Notes/Domino, Ajax, Cold Fusion, XML, MS SQL Server, and Oracle.

Microsoft Universal Development Program Partner

Comments and Discussions

 
Questionjavascript on run time control(i.e. Panel control) in asp.net using C# Pin
CHITRAKSH 20101-Apr-12 7:48
CHITRAKSH 20101-Apr-12 7:48 
GeneralNull checks Pin
Kris Moser20-Mar-09 5:46
Kris Moser20-Mar-09 5:46 
Simple observation - I copied the code and the ASP to test this out and I'm getting null exceptions everywhere that the session variables are used. Maybe some null checks on the session variables would be useful and good coding practice.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.