ASP 101 - Active Server Pages 101 - Web05
The Place ASP Developers Go!

Please visit our partners


Windows Technology Windows Technology
15 Seconds
4GuysFromRolla.com
ASP 101
ASP Wire
VB Forums
VB Wire
WinDrivers.com
internet.commerce internet.commerce
Partners & Affiliates














ASP 101 is an
internet.com site
ASP 101 is an internet.com site
IT
Developer
Internet News
Small Business
Personal Technology
International

Search internet.com
Advertise
Corporate Info
Newsletters
Tech Jobs
E-mail Offers

ASP 101 News Flash ASP 101 News Flash


 Top ASP 101 Stories Top ASP 101 Stories
VBScript Classes: Part 1 of N
Migrating to ASP.NET
Getting Scripts to Run on a Schedule

QUICK TIP:
Modifying File Timestamps
Show All Tips >>
ASP 101 RSS Feed ASP 101 Updates


Storing Data from Dynamic Controls Using ASP.NET 2.0 Callback

David Vineyard

The Problem

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.

Now that I have setup the problem, lets 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.

// 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);
}

The above code will create one TextBox per line, assigns 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.

The Solution

As stated above the solution is clean and simple. First I know 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 IE5.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.

Example:

public partial class index_aspx : System.Web.UI.Page, ICallbackEventHandler

Now in Page_Load we need to register our Client Callback.

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.

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());
    Txtid += -1;
    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 the 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.

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 manor required by your application. In this example we are simply passing the result into an alert box.

<script type="text/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);
}
</script>

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 when ever we need it.

Code Behind

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());
            //Txtid += -1;
            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("Name", "TextBox" + a);
            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();
            }
        }
    }
}

Web Form and Client Side

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "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 />
        &nbsp;
        <asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Create TextBoxes" />
        &nbsp;&nbsp;&nbsp;
        <asp:Button ID="Button2" runat="server" OnClick="Button2_Click" Text="Postback and get data" />
    </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>


Home |  News |  Samples |  Articles |  Lessons |  Resources |  Forum |  Links |  Search |  Feedback

internet.comearthweb.comDevx.commediabistro.comGraphics.com

Search:

Jupitermedia Corporation has two divisions: Jupiterimages and JupiterOnlineMedia

Jupitermedia Corporate Info

Legal Notices, Licensing, Reprints, Permissions, Privacy Policy.
Advertise | Newsletters | Tech Jobs | Shopping | E-mail Offers

Whitepapers and eBooks

Intel Whitepaper: Comparing Two- and Four-Socket Platforms for Server Virtualization
IBM Solutions Brief: Go Green With IBM System xTM And Intel
HP eBook: Simplifying SQL Server Management
IBM Contest: Are You the Next Superstar? Join the "Search for the XML Superstar" Contest to Find Out
Microsoft PDF: Top 10 Reasons to Move to Server Virtualization with Hyper-V
Microsoft PDF: Six Reasons Why Microsoft's Hyper-V Will Overtake Vmware
Microsoft Step-by-Step Guide: Hyper-V and Failover Clustering
Intel PDF: Quad-Core Impacts More Than the Data Center
Intel PDF: Virtualization Delivers Data Center Efficiency
Go Parallel Article: PDC 2008 in Review
Microsoft PDF: Top 11 Reasons to Upgrade to Windows Server 2008
Avaya Article: Communication-Enabled Mashups: Empowering Both Business Owners and IT
Intel Whitepaper: Building a Real-World Model to Assess Virtualization Platforms
  PDF: Intel Centrino Duo Processor Technology with Intel Core2 Duo Processor
Microsoft Article: Build and Run Virtual Machines with Hyper-V Server 2008
Go Parallel Article: Q&A with a TBB Junkie
IBM Whitepaper: Innovative Collaboration to Advance Your Business
Internet.com eBook: Real Life Rails
IBM eBook: The Pros and Cons of Outsourcing
Internet.com eBook: Best Practices for Developing a Web Site
IBM CXO Whitepaper: The 2008 Global CEO Study "The Enterprise of the Future"
Avaya Article: Call Control XML in Action - A CCXML Auto Attendant
IBM CXO Whitepaper: Unlocking the DNA of the Adaptable Workforce--The Global Human Capital Study 2008
Adobe Acrobat Connect Pro: Web Conferencing and eLearning Whitepapers
HP eBook: Guide to Storage Networking
MORE WHITEPAPERS, EBOOKS, AND ARTICLES