Implementing asynchronous callbacks in DropDownList controls, in ListBox controls, and in Label controls in ASP.NET 2.0

Article translations Article translations
Article ID: 910450 - View products that this article applies to.
ASP.NET Support Voice Column

Implementing asynchronous callbacks in DropDownList controls, in ListBox controls, and in Label controls in ASP.NET 2.0

To customize this column to your needs, we want to invite you to submit your ideas about topics that interest you and issues that you want to see addressed in future Knowledge Base articles and Support Voice columns. You can submit your ideas and feedback using the Ask For It form. There's also a link to the form at the bottom of this column.
Welcome to the Microsoft ASP.NET Support Voice column! I am Nilay B. Shah from the ASP.NET developer support team. I have been working with the ASP.NET support group for more than two years. Currently, I am focusing on the asynchronous callback (Client callbacks) functionality that has been added to ASP.NET 2.0. In this column, I am going to discuss a few sample applications that can be integrated into any of the ASP.NET 2.0 applications to enhance user experience. I would like to thank Jerry Orman from the ASP.NET support team for his continuous inspiration and help.
Expand all | Collapse all

On This Page

Introduction

The GridView control and the TreeView controls in ASP.NET 2.0 provide a rich, interactive user experience without full page postbacks. However, I have worked with customers who want help in performing asynchronous callbacks in other Web server controls. This article describes how the same functionality can be implemented in ListBox controls and in DropDownList controls and includes a way to increment the value of a Label control asynchronously.

The following topics are covered in this article:
  • How to update the ListBox Web server control value by using asynchronous callbacks depending on the TextBox control value
  • How to update the DropDownList Web server control value by using asynchronous callbacks depending on another DropDownList control value
  • How to increment a value in a Label control that is based on a button click in asynchronous callbacks

MORE INFORMATION

How to update the ListBox Web server control value by using asynchronous callbacks depending on the TextBox control value

To update a ListBox Web server control value by using asynchronous callbacks, follow these steps:
  1. Register callback handlers by using the Page.ClientScript.GetCallbackEventReference method.
  2. Add an appropriate attribute to the TextBox Web server control to instantiate the asynchronous callback.
  3. Retrieve the ListBox control's data based on the TextBox control value that is passed as an argument-string from the client-function, and then return the data to the client in the form of a string.
  4. Write a script to parse the Document Object Model (DOM) in the browser.
  5. Update the contents.
The following example uses a TextBox Web server control and a ListBox Web server control to display the new functionality. This sample uses the Northwind sample database's Employees table. When you start entering text for the LastName field in the TextBox control, asynchronous callbacks occur. The value of the TextBox control is passed back to the server. The employee's first name is fetched from the Employees database table depending on the text that is passed, and the data is returned to the client in a formatted string. There is a client-side JavaScript function that processes the string value and appends it to the ListBox control.

In the following code sample, the asynchronous ClientCallback script is registered to the TextBox control's OnKeyUp event in the Page_Load event of the page.
txtLastName.Attributes["OnKeyUp"] = TextBoxEventScript;
This lets the ListBox control values be retrieved based on the text that is entered in the TextBox control.

In the RaiseCallbackEvent method, the field values that match the LastName value that is passed to the server are retrieved from the database. The results of the database call are built into a pipe-delimited list in the following format:
FirstName | EmployeeID || FirstName | EmployeeID
The resulting string is sent back to the client through the GetCallbackResult function. The ReceiveServerData JavaScript function retrieves values from the delimited string and appends the values to the ListBox control.
lstFirstName.appendChild(option);
ASPX markup
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="UpdateListboxBasedOnTextbox.aspx.cs" Inherits="UpdateListboxBasedOnAnotherListbox" %>

<!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>Untitled Page</title>

    <!—JavaScript function that will run when the OnKeyUp event of the TextBox control runs on the client.  -->
    <script language="javascript">
    function ReceiveServerData(arg,context)
    {
        var lstFirstName = document.forms[0].elements['lstFirstName'];
              lstFirstName.innerHTML= "";
        var rows = arg.split('||'); 
        for (var i = 0; i < rows.length - 1; ++i)
        {
         var fields = rows[i].split('|'); 
         var firstname = fields[0];
         var employeeid = fields[1];
         var option = document.createElement("option");
         
         option.value = employeeid;
         option.innerHTML = firstname;
         lstFirstName.appendChild(option);
        }
      
    }
    </script>  
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:TextBox ID="txtLastName" runat="server" 
		Style="z-index: 100; left: 160px; position: absolute; top: 88px" Width="152px" >
	</asp:TextBox>

        <asp:ListBox ID="lstFirstName" runat="server" 
		Style="z-index: 101; left: 160px; position: absolute;top: 112px" Width="160px">
        </asp:ListBox>
        &nbsp;

        <asp:Label ID="lblLastName" runat="server" Height="16px" 
		Style="z-index: 102; left: 32px; position: absolute; top: 88px" Text="Enter Last Name:" 
		Width="120px">
        </asp:Label>

        <asp:Label ID="lblFirstName" runat="server" 
		Style="z-index: 103; left: 64px; position: absolute;top: 112px" Text="First Name:" Width="88px">
	</asp:Label>
        
	<asp:SqlDataSource ID="SqlDataSource1" runat="server" 
		ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>" 
		SelectCommand="SELECT [firstname], [lastname] FROM [Employees]">
        </asp:SqlDataSource>

        <asp:Label ID="lblText" runat="server" Font-Names="Arial" Font-Size="Small" Font-Underline="True" 
		Style="z-index: 106; left: 32px; position: absolute; top: 56px" 
		Text="Enter Employee's LastName in textbox and FirstName in Listbox Will Be Updated Asynchronously"
		Width="600px">
	</asp:Label>
    </div>
        
	<asp:Label ID="lblTitle" runat="server" Font-Bold="True" Font-Names="Verdana" 
		Style="z-index: 105;left: 8px; position: absolute; top: 16px" 
		Text="Updating ListBox Control Asynchronously"
            	Width="488px">
	</asp:Label>
        &nbsp;
	<span id="message">
	</span>
    </form>
</body>
</html>
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;
using System.Text;
using System.Data.SqlClient;
using System.Web.Configuration;


public partial class UpdateListboxBasedOnAnotherListbox : System.Web.UI.Page,ICallbackEventHandler
{

    //This object is used to build the results of the callback function
    StringBuilder arg;

    protected void Page_Load(object sender, EventArgs e)
    {
        //Do not process Page_Load if it is a clientscript callback.
        if (IsCallback)
            return;

        if (!Page.IsPostBack)
        {
            //Generate an HTML script that can instantiate an asynchronous callback onKeyUp event of 
            //txtLastName 
            string TextBoxEventScript = Page.ClientScript.GetCallbackEventReference(this, "document.all['txtLastName'].value", "ReceiveServerData", "null");
            txtLastName.Attributes["OnKeyUp"] = TextBoxEventScript;  
        }
    }


    // ********************************************************************
    // Implement the RaiseCallbackEvent function of the callback interface
    // ********************************************************************

    public void RaiseCallbackEvent(String eventArgument)
    {

	//Connect to the database and look up the employee based on the value passed to the server.
	//In this case, the textbox value is passed in the eventArgument.

        SqlConnection con = new SqlConnection(WebConfigurationManager.ConnectionStrings["NorthwindConnectionString"].ConnectionString);

        try
        {
            SqlCommand cmd = new SqlCommand();
            cmd.CommandText = "Select firstname,employeeid from Employees where LastName like @LastName";
            cmd.Parameters.Add(new SqlParameter("@LastName", SqlDbType.NVarChar, 50));
            cmd.Parameters["@LastName"].Value = eventArgument.ToString() + "%" ;
            cmd.Connection = con;

            con.Open();
            
            arg = new StringBuilder();
            
            SqlDataReader reader = cmd.ExecuteReader();

            while (reader.Read())
            {
                arg.Append(reader["firstname"]);
                arg.Append("|");
                arg.Append(reader["employeeid"]);
                arg.Append("||");
            }
            reader.Close();
        }
        catch (Exception ex)
        {
            Response.Write(ex.Message);
        }
        finally
        {
            con.Close();

        }
    }



    // ********************************************************************
    // Implement the GetCallbackResult function of the callback interface
    // ********************************************************************
    public string GetCallbackResult()
    {
        return arg.ToString();
    }
  
}

How to update the DropDownList Web server control value by using asynchronous callbacks depending on another DropDownList control value

To update the DropDownList Web server control value by using asynchronous callbacks depending on another DropDownList control value, follow these steps:
  1. Register callback handlers by using the Page.ClientScript.GetCallbackEventReference method.
  2. Add appropriate attributes to the first DropDownList Web server control to instantiate asynchronous callbacks.
  3. Retrieve the second DropDownList control's data based on the DropDownList control value that is passed from the client-side JavaScript function.
  4. Return the values to the client in the form of a delimited string.
  5. Write a script to parse the DOM in the browser, and then update the contents.
The following code sample uses two DropDownList controls, drpEmployeeId and drpEmployeeName. This sample uses the sample Northwind database's Employees table. The drpEmployeeId control is data-bound to the EmployeeId column. When you select a value from the drpEmployeeId control, an asynchronous callback occurs. The value of the drpEmployeeId control is passed back to the server. The employee's first name is retrieved from the Employees table based on the EmployeeId data that was passed from the client. The value is returned to the client in a delimited string. The client-side JavaScript function processes the string value, and then appends the values to the drpEmployeeNameDropDownList control.

ASPX markup
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="UpdateDropDownboxBasedOnAnotherDropDownBox.aspx.cs" Inherits="UpdateDropDownboxBasedOnAnotherListbox" %>

<!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>Asynchronous Callback - DropDownList</title>
    <script language="javascript">
        function ReceiveServerData(arg,context)
        {
        var drpEmployeeName = document.forms[0].elements['drpEmployeeName'];
      
        drpEmployeeName.innerHTML= "";
        var rows = arg.split('||'); 
        for (var i = 0; i < rows.length - 1; ++i)
        {
         var fields = rows[i].split('|'); 
         var firstname = fields[0];
         var employeeid = fields[1];
         var option = document.createElement("option");
         
         option.value = employeeid;
         option.innerHTML = firstname;
         drpEmployeeName.appendChild(option);
         
         document.getElementById('lblMessage').innerText = "You selected employeeid: " +  employeeid  + " for which FirstName is " + firstname ;
        
        }
        }
    </script> 
    
</head>

<body>
    <form id="form1" runat="server">
    <div>
        <asp:DropDownList ID="drpEmployeeId" runat="server" DataSourceID="SqlDataSource1"
            DataTextField="employeeid" DataValueField="employeeid" Style="z-index: 100; left: 144px;
            position: absolute; top: 112px">
        </asp:DropDownList>
        <asp:DropDownList ID="drpEmployeeName" runat="server" Style="z-index: 101; left: 144px;
            position: absolute; top: 136px">
        </asp:DropDownList>
        <asp:Label ID="lblEmployeeId" runat="server" Style="z-index: 102; left: 48px; position: absolute;
            top: 112px" Text="EmployeeID:" Width="88px"></asp:Label>
        <asp:Label ID="lblFirstName" runat="server" Style="z-index: 103; left: 48px; position: absolute;
            top: 136px" Text="First Name" Width="88px"></asp:Label>
        <asp:Label ID="lblText" runat="server" Font-Names="Arial" Font-Size="Small" Style="z-index: 104;
            left: 48px; position: absolute; top: 80px" Text="Select EmployeeId from first DropDown and Second DropDown Will Be Updated Asynchronously"
            Width="600px" Font-Underline="True"></asp:Label>
        <asp:Label ID="lblTitle" runat="server" Font-Bold="True" Font-Names="Verdana" Style="z-index: 105;
            left: 24px; position: absolute; top: 24px" Text="Updating DropDownListBox Control Asynchronously"
            Width="488px"></asp:Label>
    
    </div>
    
    <asp:Label ID="lblMessage" runat="server" Style="z-index: 107; left: 48px; position: absolute;
    top: 192px" Width="592px" Font-Names="Arial" Font-Size="Small" ForeColor="MediumBlue"></asp:Label>
    <asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>"
            SelectCommand="SELECT [employeeid], [firstname] FROM [Employees]">
    </asp:SqlDataSource>
    </form>
</body>
</html>
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;
using System.Web.Configuration;
using System.Text;
using System.Data.SqlClient;

public partial class UpdateDropDownboxBasedOnAnotherListbox : System.Web.UI.Page, ICallbackEventHandler
{
    StringBuilder arg;
    protected void Page_Load(object sender, EventArgs e)
    {
        //Do not process Page_Load if it is a clientscript callback.
        if (IsCallback)
            return;

        if (!Page.IsPostBack)
        {
            //Generate an HTML script that can instantiate an asynchronous callback on the click of 
            //the first DropDownListBox, and add it to the "onClick" attribute of the same.
            string FirstDropDownCallbackScript = Page.ClientScript.GetCallbackEventReference(this, "document.all['drpEmployeeId'].value", "ReceiveServerData", "null");
            
            drpEmployeeId.Attributes["onClick"] = FirstDropDownCallbackScript;   
              
        }
    }

    // *******************************************************
    // Implement the callback interface
    public void RaiseCallbackEvent(String eventArgument)
    {
        SqlConnection con = new SqlConnection(WebConfigurationManager.ConnectionStrings["NorthwindConnectionString"].ConnectionString);

        try
        {
            
            SqlCommand cmd = new SqlCommand();
            cmd.CommandText = "Select firstname,employeeid from Employees where employeeid= @EmployeeId";
            cmd.Parameters.Add(new SqlParameter("@EmployeeId", SqlDbType.Int, 4));
            cmd.Parameters["@EmployeeId"].Value = Int32.Parse(eventArgument);
            cmd.Connection = con;

            arg = new StringBuilder();
            con.Open();

            SqlDataReader reader = cmd.ExecuteReader();

            while (reader.Read())
            {
                arg.Append(reader["firstname"]);
                arg.Append("|");
                arg.Append(reader["employeeid"]);
                arg.Append("||");
            }
            reader.Close();
        }
        catch (Exception ex)
        {
            Response.Write(ex.Message); 
        }
        finally
        {
            con.Close();
        }
    }

    public string GetCallbackResult()
    {
        return arg.ToString() ;
    }
    // *******************************************************
}

How to increment a value in a Label control that is based on a button click in asynchronous callbacks

In the following code sample, a counter is incremented on each button click, and the value of the counter is placed in a Label control. The count value is maintained in a Session variable that is named Count to track the value across requests.

This sample uses session state to store the counter because there is no support for controlling the ViewState property in asynchronous callbacks. When you implement page properties or control properties that need to be updated during script callback operations, avoid using the ViewState property.

ASPX markup
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="IncrementingCountInLabelControl.aspx.cs" Inherits="IncrementingCountInLabelControl" %>

<!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>Asynchronous Callback - Label</title>
    <script language="javascript">
        function ReceiveServerData(arg,context)
        {
        document.getElementById('lblCounter').innerText = arg;
        }
    </script> 
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:Label ID="lblCount" runat="server" Style="z-index: 100; left: 48px; position: absolute;
            top: 80px" Text="Count :" Width="56px" Font-Names="Arial"></asp:Label>
        <asp:Label ID="lblTitle" runat="server" Font-Bold="True" Font-Names="Verdana" Style="z-index: 101;
            left: 8px; position: absolute; top: 16px" Text="Incrementing Count on each Button-Click Asynchronously"
            Width="552px"></asp:Label>
        &nbsp;&nbsp;
        <input id="btnClickMe" style="z-index: 104; left: 48px; position: absolute; top: 104px"
            type="button" onclick="CallServer('', '')" value="Click Me" />
        <asp:Label ID="lblText" runat="server" Font-Names="Arial" Font-Size="Small" Font-Underline="True"
            Style="z-index: 102; left: 32px; position: absolute; top: 48px" Text="Click Button and Observe count:"
            Width="600px"></asp:Label>
        <asp:Label ID="lblCounter" runat="server" Font-Names="Arial" Font-Size="Large" Style="z-index: 105;
            left: 104px; position: absolute; top: 80px" Text="0" Width="24px"></asp:Label>
    
    </div>
    </form>
</body>
</html>
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;
using System.Text; 

public partial class IncrementingCountInLabelControl : System.Web.UI.Page,ICallbackEventHandler 
{

    protected void Page_Load(object sender, EventArgs e)
    {
        //Do not process Page_Load if it is a clientscript callback.
        if (IsCallback)
            return;

        if (!Page.IsPostBack)
        {
            Session["Count"] = "0";
            ClientScriptManager cm = Page.ClientScript;
            String cbReference = cm.GetCallbackEventReference(this, "arg", "ReceiveServerData", "");
            String callbackScript = "function CallServer(arg, context) {" + cbReference + "; }";
            cm.RegisterClientScriptBlock(this.GetType(), "CallServer", callbackScript, true);
        }
 
    }

    // *******************************************************
    // Implement the callback interface
    public void RaiseCallbackEvent(String eventArgument)
    {
          Session["Count"]  = int.Parse((Session["Count"].ToString())) + 1;
    }

    public string GetCallbackResult()
    {
        return Session["Count"].ToString(); 
    }
    // *******************************************************


    }

Conclusion

Although asynchronous callbacks are limited in terms of passing the values from the client to the server as a string and requiring you to write some Javascript, it is possible to update Web server controls other than the GridView control and the TreeView control asynchronously. A little extra effort can enhance the user experience to a great extent!

Related links

For more information, visit the following Microsoft Web sites:
http://msdn2.microsoft.com/en-us/library/ms178208(VS.80).aspx
http://msdn.microsoft.com/msdnmag/issues/04/08/CuttingEdge/
http://msdn2.microsoft.com/en-us/library/ms153103(VS.80).aspx
http://msdn2.microsoft.com/en-us/library/ms189826.aspx
For more information about DOM HTML, visit the following World Wide Web Consortium (W3C) Web site:
http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-642250288
I hope you found this information helpful. Remember, the Support Voice columns are for you! As always, feel free to submit ideas on topics you want addressed in future columns or in the Knowledge Base using the Ask For It form.

Properties

Article ID: 910450 - Last Review: December 14, 2006 - Revision: 1.2
APPLIES TO
  • Microsoft ASP.NET 2.0
Keywords: 
kbhowto kbasp KB910450
Retired KB Content Disclaimer
This article was written about products for which Microsoft no longer offers support. Therefore, this article is offered "as is" and will no longer be updated.

Give Feedback

 

Contact us for more help

Contact us for more help
Connect with Answer Desk for expert help.
Get more support from smallbusiness.support.microsoft.com