LanceZhang’s Blog

Dear friends, Welcome to my blog.

TinyMCE Editor and Ajax Control Toolkit Tab Control

As we know, the ASP.NET forum’s add post page contains a TabContainer control in one TabPanel there is a TinyMCE Editor for edit the post, another TabPanel is use for preview the post.

In this case, I have created a demo like that:

<%@ Page Language=”C#” ValidateRequest=”false” %>

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”&gt;

<script runat=“server”>

</script>

<html xmlns=http://www.w3.org/1999/xhtml&#8221;>
<head id=“Head1” runat=“server”>
    <title></title>
    <!– TinyMCE –>

    <script src=“tiny_mce/tiny_mce.js” type=“text/javascript”></script>

    <script type=“text/javascript”>
        tinyMCE.init({
            // General options
            mode: “textareas”,
            theme: “advanced”,
            plugins: “safari,pagebreak,style,layer,table,save,advhr,advimage,advlink,emotions,iespell,inlinepopups,

insertdatetime,preview,media,searchreplace,print,contextmenu,paste,directionality,fullscreen,noneditable,visualchars,nonbreaking,xhtmlxtras,template”,

            // Theme options
            theme_advanced_buttons1: “save,newdocument,|,bold,italic,underline,strikethrough,|

,justifyleft,justifycenter,justifyright,justifyfull,styleselect,formatselect,fontselect,fontsizeselect”,
            theme_advanced_buttons2: “cut,copy,paste,pastetext,pasteword,|,search,replace,|,bullist,numlist,|,outdent,indent,blockquote,|

,undo,redo,|,link,unlink,anchor,image,cleanup,help,code,|,insertdate,inserttime,preview,|,forecolor,backcolor”,
            theme_advanced_buttons3: “tablecontrols,|,hr,removeformat,visualaid,|,sub,sup,|,charmap,emotions,iespell,media,advhr,|

,print,|,ltr,rtl,|,fullscreen”,
            theme_advanced_buttons4: “insertlayer,moveforward,movebackward,absolute,|,styleprops,|,cite,abbr,acronym,del,ins,attribs,

|,visualchars,nonbreaking,template,pagebreak”,
            theme_advanced_toolbar_location: “top”,
            theme_advanced_toolbar_align: “left”,
            theme_advanced_statusbar_location: “bottom”,
            theme_advanced_resizing: true,

            // Example content CSS (should be your site CSS)
            content_css: “css/content.css”,

            // Drop lists for link/image/media/template dialogs
            template_external_list_url: “lists/template_list.js”,
            external_link_list_url: “lists/link_list.js”,
            external_image_list_url: “lists/image_list.js”,
            media_external_list_url: “lists/media_list.js”,

            // Replace values for the template plugin
            template_replace_values: {
                username: “Some User”,
                staffid: “991234”
            }
        });
    </script>

    <!– /TinyMCE –>
</head>
<body>
    <form id=“form1” runat=“server”>
    <div>
        <asp:ScriptManager ID=“ScriptManager1” runat=“server”>
        </asp:ScriptManager>
        <ajaxToolkit:TabContainer ID=“TabContainer1” runat=“server” ActiveTabIndex=“0” Height=“300px”
            Width=“100%” OnClientActiveTabChanged=“preview”>
            <ajaxToolkit:TabPanel runat=“server” HeaderText=“Edit Post” ID=“TabPanel1”>
                <ContentTemplate>
                    <!– Gets replaced with TinyMCE, remember HTML in a textarea should be encoded –>
                    <textarea id=“elm1” name=“elm1” rows=“15” cols=“80” style=“width: 99%; height: 280px;”>
        <p>
        <img src=“media/logo.jpg” alt=” “ hspace=“5” vspace=“5” width=“250” height=“48” align=“right” />    TinyMCE is a platform independent web based Javascript HTML <strong>WYSIWYG</strong> editor control released as Open Source under LGPL by Moxiecode Systems AB. It has the ability to convert HTML TEXTAREA fields or other HTML elements to editor instances. TinyMCE is very easy to integrate into other Content Management Systems.
        </p>
        <p>
        We recommend <a href=http://www.getfirefox.com&#8221; target=“_blank”>Firefox</a> and <a href=http://www.google.com&#8221; target=“_blank”>Google</a> <br />
        </p>
    </textarea>
                </ContentTemplate>
            </ajaxToolkit:TabPanel>
            <ajaxToolkit:TabPanel runat=“server” HeaderText=“Preview” ID=“TabPanel2”>
                <ContentTemplate>
                    <asp:Label ID=“Label1” runat=“server” Text=“Label”></asp:Label>
                </ContentTemplate>
            </ajaxToolkit:TabPanel>
            <ajaxToolkit:TabPanel runat=“server” HeaderText=“TabPanel3” ID=“TabPanel3”>
                <ContentTemplate>
                    Other
                </ContentTemplate>
            </ajaxToolkit:TabPanel>
        </ajaxToolkit:TabContainer>
        <asp:Button ID=“Button1” runat=“server” Text=“Button” OnClientClick=“document.write(tinyMCE.get(‘elm1’).getContent());return false;” />
    </div>

    <script type=“text/javascript”>

        function preview() {
            if ($find(“TabContainer1”).get_activeTabIndex() == 1) {
                $get(“<%=Label1.ClientID %>”).innerHTML = tinyMCE.get(‘elm1’).getContent();
            }
        }
    </script>

    </form>
</body>
</html>

January 20, 2009 Posted by | ASP.NET AJAX, ASP.NET AJAX Advance Tips & Tricks, Code and Solution, JavaScript | , , | 1 Comment

Create Tooltip dynamically by AJAX and WebService

Use Pop up div by JavaScript or AJAX Control Toolkit’s Hover Menu control can create a Tooltip easily.

However, if we need to create the content of tooltip dynamically by the Server-Side code, we can use the ICallbackEventHandler to achieve the faing goal, just like the solution in following link:

https://lancezhang.wordpress.com/2008/12/04/create-tooltip-dynamically/

When you move the mouse on the text, the related image and text which will be created on the code-behind show up in the tooltip after 1 second. during the loading process, a “loading” gif picture will display in the tooltip box.

If we are using ASP.NET AJAX, the same effect can be achieve by AJAX Page Method easily, just like the solution in following link:

https://lancezhang.wordpress.com/2009/01/12/create-tooltip-dynamically-by-ajax-pagemethod/

And we can also use WebService and AJAX to achieve the same goal.

Ok, here we go:

Step 1:

First, let’s add the WebService reference to our page:

<asp:ScriptManager ID=“ScriptManager1” runat=“server”>
    <Services>
        <asp:ServiceReference Path=“~/tooltiptest3.asmx” />
    </Services>
</asp:ScriptManager>

Step 2:

Let’s create the WebService for create tooltip message:

<%@ WebService Language=“C#” Class=“tooltiptest3” %>

using System;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;

[WebService(Namespace = “http://tempuri.org/&#8221;)]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
// To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
[System.Web.Script.Services.ScriptService]
public class tooltiptest3  : System.Web.Services.WebService {

    [WebMethod]
    public string GetTooltip(string imagename)
    {
        System.Threading.Thread.Sleep(1000);
        return @”this is just a demo: <br><img src='” + imagename + “‘/>”;
    }
   
}

Step 3:

Complete the JavaScript code to invoke the page method:

<script type=“text/javascript”>
    var positionX;
    var positionY;

    function onSuccess(value) {
        document.getElementById(‘tooltipDiv’).innerHTML = value;
    }

    function onFailed(ex, ctx, methodName) {
        alert(ex.get_exceptionType());
    }

    function HandleMouseOut() {
        document.getElementById(‘tooltipDiv’).style.display = ‘none’;
        document.getElementById(‘tooltipDiv’).innerHTML = “<img src=’loading.gif’/>”;
    }

    function HandleMouseOver(Label) {

        tooltiptest3.GetTooltip(Label.innerText, onSuccess, onFailed);

        positionX = event.clientX;
        positionY = event.clientY;
        document.getElementById(‘tooltipDiv’).style.left = positionX;
        document.getElementById(‘tooltipDiv’).style.top = positionY;
        document.getElementById(‘tooltipDiv’).style.display = ‘block’;
    }
          
   
</script>

OK, the full page code is following:

<%@ Page Language=”C#” %>

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”&gt;

<script runat=“server”>

</script>

<html xmlns=http://www.w3.org/1999/xhtml&#8221;>
<head id=“Head1” runat=“server”>

    <script type=“text/javascript”>
        var positionX;
        var positionY;

        function onSuccess(value) {
            document.getElementById(‘tooltipDiv’).innerHTML = value;
        }

        function onFailed(ex, ctx, methodName) {
            alert(ex.get_exceptionType());
        }

        function HandleMouseOut() {
            document.getElementById(‘tooltipDiv’).style.display = ‘none’;
            document.getElementById(‘tooltipDiv’).innerHTML = “<img src=’loading.gif’/>”;
        }

        function HandleMouseOver(Label) {

            tooltiptest3.GetTooltip(Label.innerText, onSuccess, onFailed);

            positionX = event.clientX;
            positionY = event.clientY;
            document.getElementById(‘tooltipDiv’).style.left = positionX;
            document.getElementById(‘tooltipDiv’).style.top = positionY;
            document.getElementById(‘tooltipDiv’).style.display = ‘block’;
        }
              
       
    </script>

    <style type=“text/css”>
        .style1
        {
            border: 1px solid #96C2F1;
            background-color: #EFF7FF;
            position: absolute;
            display: none;
            filter: alpha(opacity=80);
            opacity: 0.80;
        }
    </style>
    <title>Untitled Page</title>
</head>
<body style=“font-family: Calibri; font-size: 15px;”>
    <form id=“form1” runat=“server”>
    <asp:ScriptManager ID=“ScriptManager1” runat=“server”>
        <Services>
            <asp:ServiceReference Path=“~/tooltiptest3.asmx” />
        </Services>
    </asp:ScriptManager>
    <div id=“tooltipDiv” class=“style1”>
        <img src=“loading.gif” />
    </div>
    <div>
        <asp:Label ID=“Label1” runat=“server” Text=http://forums.asp.net/Themes/FAN/style/i/logo.png&#8221;
            onmouseout=“HandleMouseOut()” onmouseover=“HandleMouseOver(this)”></asp:Label>
        <br />
        <br />
        <br />
        <br />
        <asp:Label ID=“Label2” runat=“server” Text=http://forums.asp.net/Themes/fan/images/roleicons/a874d69e-0ac8-4b80-acc7-512767e281f6.gif&#8221;
            onmouseout=“HandleMouseOut()” onmouseover=“HandleMouseOver(this)”></asp:Label>
    </div>
    </form>
</body>
</html>

January 12, 2009 Posted by | ASP.NET, ASP.NET AJAX, ASP.NET AJAX Advance Tips & Tricks, Code and Solution, Uncategorized | , , , | 2 Comments

Create Tooltip dynamically by AJAX PageMethod

Use Pop up div by JavaScript or AJAX Control Toolkit’s Hover Menu control can create a Tooltip easily.

However, if we need to create the content of tooltip dynamically by the Server-Side code, we can use the ICallbackEventHandler to achieve the faing goal, just like the solution in following link:

https://lancezhang.wordpress.com/2008/12/04/create-tooltip-dynamically

When you move the mouse on the text, the related image and text which will be created on the code-behind show up in the tooltip after 1 second. during the loading process, a “loading” gif picture will display in the tooltip box.

If we are using ASP.NET AJAX, the same effect can be achieve by AJAX Page Method easily.

Ok, here we go:

Step 1:

we need to set the EnablePageMethods=”true” for our ScriptManager or ToolkitScriptManager:

<asp:ScriptManager ID=“ScriptManager1” runat=“server” EnablePageMethods=“true”>
</asp:ScriptManager>

Step 2:

Let’s create the Server-side method for create tooltip message, please notice the using references and attribute:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Script.Services;
using System.Web.Services;
using System.Web.UI;
using System.Web.UI.WebControls;

[ScriptService]
public partial class tooltiptest2 : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {

    }

    [WebMethod]
    public static string GetTooltip(string imagename)
    {
        System.Threading.Thread.Sleep(1000);
        return @”this is just a demo: <br><img src='” + imagename + “‘/>”;
    }
}

 

Step 3:

Complete the JavaScript code to invoke the page method:

<script type=“text/javascript”>
    var positionX;
    var positionY;

    function onSuccess(value, ctx, methodName) {
        document.getElementById(‘tooltipDiv’).innerHTML = value;
    }

    function onFailed(ex, ctx, methodName) {
        alert(ex.get_exceptionType());
    }

    function HandleMouseOut() {
        document.getElementById(‘tooltipDiv’).style.display = ‘none’;
        document.getElementById(‘tooltipDiv’).innerHTML = “<img src=’loading.gif’/>”;
    }

    function HandleMouseOver(Label) {

        PageMethods.GetTooltip(Label.innerText, onSuccess, onFailed);

        positionX = event.clientX;
        positionY = event.clientY;
        document.getElementById(‘tooltipDiv’).style.left = positionX;
        document.getElementById(‘tooltipDiv’).style.top = positionY;
        document.getElementById(‘tooltipDiv’).style.display = ‘block’;
    }
  
</script>

OK, the full code is following:

<%@ Page Language=”C#” AutoEventWireup=”true” CodeFile=”tooltiptest2.aspx.cs” Inherits=”tooltiptest2″ %>

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”&gt;
<html xmlns=http://www.w3.org/1999/xhtml&#8221;>
<head id=“Head1” runat=“server”>

    <script type=“text/javascript”>
        var positionX;
        var positionY;

        function onSuccess(value, ctx, methodName) {
            document.getElementById(‘tooltipDiv’).innerHTML = value;
        }

        function onFailed(ex, ctx, methodName) {
            alert(ex.get_exceptionType());
        }

        function HandleMouseOut() {
            document.getElementById(‘tooltipDiv’).style.display = ‘none’;
            document.getElementById(‘tooltipDiv’).innerHTML = “<img src=’loading.gif’/>”;
        }

        function HandleMouseOver(Label) {

            PageMethods.GetTooltip(Label.innerText, onSuccess, onFailed);

            positionX = event.clientX;
            positionY = event.clientY;
            document.getElementById(‘tooltipDiv’).style.left = positionX;
            document.getElementById(‘tooltipDiv’).style.top = positionY;
            document.getElementById(‘tooltipDiv’).style.display = ‘block’;
        }
      
    </script>

    <style type=“text/css”>
        .style1
        {
            border: 1px solid #96C2F1;
            background-color: #EFF7FF;
            position: absolute;
            display: none;
            filter: alpha(opacity=80);
            opacity: 0.80;
        }
    </style>
    <title>Untitled Page</title>
</head>
<body style=“font-family: Calibri; font-size: 15px;”>
    <form id=“form1” runat=“server”>
    <asp:ScriptManager ID=“ScriptManager1” runat=“server” EnablePageMethods=“true”>
    </asp:ScriptManager>
    <div id=“tooltipDiv” class=“style1”>
        <img src=“loading.gif” />
    </div>
    <div>
        <asp:Label ID=“Label1” runat=“server” Text=http://forums.asp.net/Themes/FAN/style/i/logo.png&#8221;
            onmouseout=“HandleMouseOut()” onmouseover=“HandleMouseOver(this)”></asp:Label>
        <br />
        <br />
        <br />
        <br />
        <asp:Label ID=“Label2” runat=“server” Text=http://forums.asp.net/Themes/fan/images/roleicons/a874d69e-0ac8-4b80-acc7-512767e281f6.gif&#8221;
            onmouseout=“HandleMouseOut()” onmouseover=“HandleMouseOver(this)”></asp:Label>
    </div>
    </form>
</body>
</html>

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Script.Services;
using System.Web.Services;
using System.Web.UI;
using System.Web.UI.WebControls;

[ScriptService]
public partial class tooltiptest2 : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {

    }

    [WebMethod]
    public static string GetTooltip(string imagename)
    {
        System.Threading.Thread.Sleep(1000);
        return @”this is just a demo: <br><img src='” + imagename + “‘/>”;
    }
}

January 12, 2009 Posted by | ASP.NET, ASP.NET AJAX, ASP.NET AJAX Advance Tips & Tricks, Code and Solution, JavaScript | , , | 6 Comments

How to change the Culture of CalendarExtender programmatically

Based on my knowledge, the CalendarExtender’s language is based on the “Sys.CultureInfo.CurrentCulture.dateTimeFormat”, all of the primary function “_buildDays” “_buildMonths”  “_performLayout”  “_getFirstDayOfWeek” use the “Sys.CultureInfo.CurrentCulture.dateTimeFormat”.

So, if we need change the language or culture of CalendarExtender, we need to change the “Sys.CultureInfo.CurrentCulture.dateTimeFormat”.

There are two ways can change the “Sys.CultureInfo.CurrentCulture.dateTimeFormat”:

1. Change the CurrentCulture in code-behind, by the following code: 

protected void Page_Load(object sender, EventArgs e)
{
    string Lang = “ro-RO”;//set your culture here
    System.Threading.Thread.CurrentThread.CurrentCulture =
        new System.Globalization.CultureInfo(Lang);
}

If you add the following code to your page, and set the EnableScriptGlobalization=”true” to your ToolkitScriptManager or ScriptManager, the language and culture of CalendarExtender will be “ro-RO” (more culture symbol, please visit: http://msdn.microsoft.com/en-us/library/system.globalization.cultureinfo(VS.80).aspx)

2. Change the Sys.CultureInfo.CurrentCulture.dateTimeFormat by JavaScript, and then, dispose and recreate the CalendarExtender.

<script type=“text/javascript”>

    function pageLoad(sender, args) {

        //Step1:
        //dispose the original CalendarExtender, change “CalendarExtender2” to the BehaviorID of your CalendarExtender
        $find(“CalendarExtender2”).dispose();

        //Step2:
        //change the “Sys.CultureInfo.CurrentCulture.dateTimeFormat, as your wish”
        Sys.CultureInfo.CurrentCulture.dateTimeFormat.FirstDayOfWeek = 3;
        Sys.CultureInfo.CurrentCulture.dateTimeFormat.ShortestDayNames = [“0”, “1”, “2”, “3”, “4”, “5”, “6”];

        //Step3:
        //Recreate the CalendarExtender
        $create(AjaxControlToolkit.CalendarBehavior, { “button”: $get(“image2”), “id”: “CalendarExtender2”, “popupPosition”: 1 }, null, null, $get(“TextBox1”));
    }     
         
</script>

 Also, we need make sure the EnableScriptGlobalization=”true” to your ToolkitScriptManager or ScriptManager.

For more information about “Sys.CultureInfo.CurrentCulture.dateTimeFormat”, please visit:
http://msdn.microsoft.com/en-us/library/bb397445.aspx

For more information about create Extenders by $create, please visit:

ASP.NET AJAX Control Toolkit FAQ: 6.2 How do I create a ModalPopup programmatically?
http://forums.asp.net/t/992919.aspx

The full page demo is following:

<%@ Page Language=”C#” %>

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”&gt;

<script runat=“server”>

    protected void Page_Load(object sender, EventArgs e)
    {
        string Lang = “ro-RO”;//set your culture here
        System.Threading.Thread.CurrentThread.CurrentCulture =
            new System.Globalization.CultureInfo(Lang);
    }
</script>

<html xmlns=http://www.w3.org/1999/xhtml&#8221;>
<head id=“Head1” runat=“server”>
    <title></title>
</head>
<body>
    <form id=“form1” runat=“server”>
    <ajaxToolkit:ToolkitScriptManager ID=“ToolkitScriptManager1” runat=“server” EnableScriptGlobalization=“true”>
    </ajaxToolkit:ToolkitScriptManager>
    <div>
        <asp:TextBox ID=“TextBox1” runat=“server”></asp:TextBox>
        <ajaxToolkit:CalendarExtender ID=“CalendarExtender2” runat=“server” TargetControlID=“TextBox1”
            FirstDayOfWeek=“default” PopupButtonID=“image2” Enabled=“True” PopupPosition=“BottomRight”
            BehaviorID=“CalendarExtender2”>
        </ajaxToolkit:CalendarExtender>
    </div>

    <script type=“text/javascript”>

        function pageLoad(sender, args) {

            //Step1:
            //dispose the original CalendarExtender, change “CalendarExtender2” to the BehaviorID of your CalendarExtender
            $find(“CalendarExtender2”).dispose();

            //Step2:
            //change the “Sys.CultureInfo.CurrentCulture.dateTimeFormat, as your wish”
            Sys.CultureInfo.CurrentCulture.dateTimeFormat.FirstDayOfWeek = 3;
            Sys.CultureInfo.CurrentCulture.dateTimeFormat.ShortestDayNames = [“0”, “1”, “2”, “3”, “4”, “5”, “6”];

            //Step3:
            //Recreate the CalendarExtender
            $create(AjaxControlToolkit.CalendarBehavior, { “button”: $get(“image2”), “id”: “CalendarExtender2”, “popupPosition”: 1 }, null, null, $get(“TextBox1”));
        }     
             
    </script>

    </form>
</body>
</html>

Thanks.

January 9, 2009 Posted by | ASP.NET AJAX, ASP.NET AJAX Advance Tips & Tricks, Code and Solution | , | 8 Comments

Create Tooltip dynamically by ASP.NET Callback

Use Pop up div by JavaScript or AJAX Control Toolkit’s Hover Menu control can create a Tooltip easily.

However, if we need to create the content of tooltip dynamically by the Server-Side code, we can use the ICallbackEventHandler to achieve the faing goal.

Please try the following demo, when you move the mouse on the text, the related image and text which will be created on the code-behind show up in the tooltip after 1 second. during the loading process, a “loading” gif picture will display in the tooltip box.

Ok, here we go:

<%@ Page Language=”C#” AutoEventWireup=”true” CodeFile=”tooltiptest.aspx.cs” Inherits=”tooltiptest” %>

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”&gt;
<html xmlns=http://www.w3.org/1999/xhtml&#8221;>
<head id=“Head1” runat=“server”>

    <script type=“text/javascript”>
        var positionX;
        var positionY;
        function HandleMouseOver(Label) {
            CallTheServer(Label.innerText, );
            positionX = event.clientX;
            positionY = event.clientY;
            document.getElementById(‘tooltipDiv’).style.left = positionX;
            document.getElementById(‘tooltipDiv’).style.top = positionY;
            document.getElementById(‘tooltipDiv’).style.display = ‘block’;
        }
        function HandleMouseOut() {
            document.getElementById(‘tooltipDiv’).style.display = ‘none’;
            document.getElementById(‘tooltipDiv’).innerHTML = “<img src=’loading.gif’/>”;
        }
        function ReceiveServerData(arg, context) {
            document.getElementById(‘tooltipDiv’).innerHTML = arg;
        }
    </script>

    <style type=“text/css”>
        .style1
        {
            border: 1px solid #96C2F1;
            background-color: #EFF7FF;
            position: absolute;
            display: none;
            filter: alpha(opacity=80);
            opacity: 0.80;
        }
    </style>
    <title>Untitled Page</title>
</head>
<body style=“font-family: Calibri; font-size: 15px;”>
    <form id=“form1” runat=“server”>
    <div id=“tooltipDiv” class=“style1”>
    <img src=“loading.gif”/>
    </div>
    <div>
        <asp:Label ID=“Label1” runat=“server” Text=http://forums.asp.net/Themes/FAN/style/i/logo.png&#8221;
            onmouseout=“HandleMouseOut()” onmouseover=“HandleMouseOver(this)”></asp:Label>
        <br />
        <br />
        <br />
        <br />
        <asp:Label ID=“Label2” runat=“server” Text=http://forums.asp.net/Themes/fan/images/roleicons/a874d69e-0ac8-4b80-acc7-512767e281f6.gif&#8221;
            onmouseout=“HandleMouseOut()” onmouseover=“HandleMouseOver(this)”></asp:Label>
    </div>
    </form>
</body>
</html> 

 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class tooltiptest : System.Web.UI.Page, System.Web.UI.ICallbackEventHandler
{
    string tooltip;

    public void RaiseCallbackEvent(String eventArgument)
    {
        string filename = eventArgument;
        tooltip = GetTooltip(filename);
    }

    public string GetCallbackResult()
    {
        return tooltip;
    }

    protected string GetTooltip(string imagename)
    {
        System.Threading.Thread.Sleep(1000);
        return @”this is just a demo: <br><img src='” + imagename+“‘/>”;
    }

    protected void Page_Load(object sender, EventArgs e)
    {
        String cbReference = Page.ClientScript.GetCallbackEventReference(this, “arg”, “ReceiveServerData”, “context”);
        String callbackScript = “function CallTheServer(arg, context) {“ + cbReference + “; }”;
        Page.ClientScript.RegisterClientScriptBlock(this.GetType(), “CallTheServer”, callbackScript, true);
    }
}

December 4, 2008 Posted by | ASP.NET, ASP.NET AJAX | , | 4 Comments

ASP.NET AJAX Performance Improvement

Preface

I think everyone would agree that AJAX is one of the elements of “Web 2.0”,  every web developers should know this technology. I have been collected a list of the popular AJAX Frameworks on my chinese tech blog, we will amazedly found that, there are more than 128 AJAX Frameworks!

ajax-frameworks1

Refer to a voting result, among the 95% of the .NET developers that said they are using some flavor of Ajax either in production, development or prototype, the most used AJAX Framework is ASP.NET AJAX, with 73,7%, followed by the Ajax Control Toolkit which is used by almost half of the .NET developer that are using Ajax.

However, many beginners always complain that, using ASP.NET AJAX make their web application slow down, don’t perform as well as they had hoped.  Today, I would like to share some experience on how to optimize the ASP.NET AJAX application.

So I created a simple page with a bunch of extenders on it: CalendarExtender, SliderExtender, NumericUpDownExtender, RoundedCornersExtender, and TabContainer for our experiments.

And I would like to introduce two useful tools for our Performance Analysis:

1. HttpWatch to show the network traffic.

Here’s how the network traffic looked before any optimization:

And we can see there are totally 22 requests and spend 9 seconds to get the 654k result. It is a really terrible in performance.

without-any-optimizations

2. ScriptReferenceProfiler to show the JavaScript reference.

ScriptReferenceProfiler is an open source tool on CodePlex, for analysis the JavaScript references of ASP.NET AJAX, we can simply add the following code to our page in order to show the JavaScript references imported by ScriptManager.

<microsoft:scriptreferenceprofiler runat=“server”>
</microsoft:scriptreferenceprofiler>

We can see, before any optimization, there are 17 references found on this page, include the Microsoft Ajax Core runtime, asynchronous postback scripts, Ajax Control Toolkit Extender scripts and so on:

references-without-any-optimizations1

Optimization in web.config

To optimize the ASP.NET AJAX in our web application, first of all, we need to make sure the Compression and Caching is enabled in our web.config:

<system.web.extensions>
<scripting>
<scriptResourceHandler enableCompression=“true” enableCaching=“true”/>
</scripting>
</system.web.extensions>

1. Enable The Caching:

We know, in the development of web application, enable the caching is a must operation. To enable the caching of ASP.NET AJAX, we need make sure the enableCaching property of scriptResourceHandler is set to true.

As our expected, the page response more quickly in the second time, the expend time is coming from 12.862 seconds down to 0.409seconds; and the received size from server decrease from 692K to 14K.

without-cachingwith-caching

2. Enable The Compression:

The Caching will saving almost 95% of the network traffic in the second time we request the page, however, the first page request still ask for a huge data from server. How to reduce the first request? don’t worry, set enableCompression property of scriptResourceHandler to true will help:

without-compressionwith-compression

As we can see in the screen shot, many script files are getting smaller. and the total size decrease form 692K to 183K, about 1/4 compare to before.

♣Note: The compression is not work in Internet Explorer 6.0, because there is an known bug in IE 6, that cause the mistake might be occur when receiving the Gzip header. So the develop team close all the compression ability in IE 6.

Optimization in ScriptManager

The ScriptManager control manages client script for AJAX-enabled ASP.NET Web pages. By default, the ScriptManager control registers the script for the Microsoft AJAX Library with the page. This enables client script to use the type system extensions and to support features such as partial-page rendering and Web-service calls. Following, we need to setting the property of ScriptManager to optimize the performance of ASP.NET AJAX.

1. ScriptMode for Release

In one of Scott Guthrie’s post, he explain that we should avoid when deploying an ASP.NET application into production  leave the <compilation debug=”true”/> switch on within the application’s web.config file.

It will cause:

1) The compilation of ASP.NET pages takes longer (since some batch optimizations are disabled)

2) Code can execute slower (since some additional debug paths are enabled)

3) Much more memory is used within the application at runtime

4) Scripts and images downloaded from the WebResources.axd handler are not cached

In this scenario, we can set the ScriptManager on the page run into the release mode to like the following:

<asp:ScriptManager ID=”ScriptManager1″ runat=”server” ScriptMode=”Release”>

</asp:ScriptManager>

2. EnablePartialRendering Yes or No?

There is another property in ScriptManager named EnablePartialRendering,  it gets or sets a value that enables partial rendering of a page, which in turn enables you to update regions of the page individually by using UpdatePanel controls.

So, if we using the UpdatePanel in the page, we must set this property to true, conversely, if the UpdatePanel is not using in our page, it would be better that we set the EnablePartialRendering to false.

That will cause the unnecessary file “MicrosoftAjaxWebForm.js”, which is used to the partial rendering not import to our page.

<asp:ScriptManager ID=”ScriptManager1″ runat=”server” EnablePartialRendering=”false”>

</asp:ScriptManager>

disable-partial-rendering

3. LoadScriptBeforeUI

ScriptManager control has LoadScriptsBeforeUI property which we can set to “False” in order to postpone several script downloads after the content is downloaded and shown. This adds the script references end of the <body> tag. As a result, we will see the content first and then the additional scripts, exteders, AJAX Control Toolkit scripts get downloaded and initialized.

This will make the page show quikly, and provide a better User Experience.

Script Combining

In the previous talk, we can see the download size is coming down, but the number of requests is still more than 20

1. ToolkitScriptManager

There is a ToolkitScriptManager control in the AJAX Control Toolkit, we can replace the default <asp:scriptmanager> control with this, it supports the ability to dynamically merge multiple client-side Javascript scripts into a single file that is downloaded to the client at runtime.  Better yet, only the Javascript needed by the specific controls on the page are included within the combined download, to make it as small as possible.

scriptmanagertoolkitscriptmanager

As the screen shot shows, It is a big savings in requests –  we now get one request for Toolkit scripts instead of 12.  In this scenario, we also got about a 50% download speed improvement by only having one request.

2. CompositeScript

If you are using ASP.NET 3.5 with SP1, there is a more powerful tool to combining the Script file – CompositeScript.

First, We can use the ScriptReferenceProfiler to show the JavaScript references

and then, we can add <CompositeScript> and <Scripts> elements as children of the ScriptManager control.

Then, Copy the script references from the page and paste them into the <Scripts> element inside the ScriptManager control, the result mark up is following:

<asp:ScriptManager ID=”ScriptManager1″ runat=”server” EnablePartialRendering=”false” ScriptMode=”Release” LoadScriptsBeforeUI=”false”>

<CompositeScript>

<Scripts>

<asp:ScriptReference Name=”MicrosoftAjax.js” />

<asp:ScriptReference Name=”AjaxControlToolkit.Common.Common.js” Assembly=”AjaxControlToolkit, Version=3.0.20229.23352, Culture=neutral, PublicKeyToken=28f01b0e84b6d53e” />

<asp:ScriptReference Name=”AjaxControlToolkit.ExtenderBase.BaseScripts.js” Assembly=”AjaxControlToolkit, Version=3.0.20229.23352, Culture=neutral, PublicKeyToken=28f01b0e84b6d53e” />

<asp:ScriptReference Name=”AjaxControlToolkit.Tabs.Tabs.js” Assembly=”AjaxControlToolkit, Version=3.0.20229.23352, Culture=neutral, PublicKeyToken=28f01b0e84b6d53e” />

<asp:ScriptReference Name=”AjaxControlToolkit.DynamicPopulate.DynamicPopulateBehavior.js”

Assembly=”AjaxControlToolkit, Version=3.0.20229.23352, Culture=neutral, PublicKeyToken=28f01b0e84b6d53e” />

<asp:ScriptReference Name=”AjaxControlToolkit.Common.DateTime.js” Assembly=”AjaxControlToolkit, Version=3.0.20229.23352, Culture=neutral, PublicKeyToken=28f01b0e84b6d53e” />

<asp:ScriptReference Name=”AjaxControlToolkit.Compat.Timer.Timer.js” Assembly=”AjaxControlToolkit, Version=3.0.20229.23352, Culture=neutral, PublicKeyToken=28f01b0e84b6d53e” />

<asp:ScriptReference Name=”AjaxControlToolkit.Animation.Animations.js” Assembly=”AjaxControlToolkit, Version=3.0.20229.23352, Culture=neutral, PublicKeyToken=28f01b0e84b6d53e” />

<asp:ScriptReference Name=”AjaxControlToolkit.Animation.AnimationBehavior.js” Assembly=”AjaxControlToolkit, Version=3.0.20229.23352, Culture=neutral, PublicKeyToken=28f01b0e84b6d53e” />

<asp:ScriptReference Name=”AjaxControlToolkit.PopupExtender.PopupBehavior.js” Assembly=”AjaxControlToolkit, Version=3.0.20229.23352, Culture=neutral, PublicKeyToken=28f01b0e84b6d53e” />

<asp:ScriptReference Name=”AjaxControlToolkit.Common.Threading.js” Assembly=”AjaxControlToolkit, Version=3.0.20229.23352, Culture=neutral, PublicKeyToken=28f01b0e84b6d53e” />

<asp:ScriptReference Name=”AjaxControlToolkit.Calendar.CalendarBehavior.js” Assembly=”AjaxControlToolkit, Version=3.0.20229.23352, Culture=neutral, PublicKeyToken=28f01b0e84b6d53e” />

<asp:ScriptReference Name=”AjaxControlToolkit.Compat.DragDrop.DragDropScripts.js”

Assembly=”AjaxControlToolkit, Version=3.0.20229.23352, Culture=neutral, PublicKeyToken=28f01b0e84b6d53e” />

<asp:ScriptReference Name=”AjaxControlToolkit.Slider.SliderBehavior.js” Assembly=”AjaxControlToolkit, Version=3.0.20229.23352, Culture=neutral, PublicKeyToken=28f01b0e84b6d53e” />

</Scripts>

</CompositeScript>

</asp:ScriptManager>

Run the page and view the traffic. We will see just one script reference now instead of all the script inside the <Scripts> element.

combining

November 15, 2008 Posted by | ASP.NET AJAX | , | 36 Comments

ASP.NET AJAX Advance Tips & Tricks (2) Create Rating Control dynamically

Preface:

Rating control of AJAX Control Toolkit are already widely used, However, many of my friends recently complained that if they create Rating control in code-behind dynamically, then, the Rating status will be lost after a PostBack(not into ViewState). This article describes two ways to solve the problem.

To reproduce the problem:

If we use the following code to create Rating control dynamically, then after the Button click, Rating selected value will be lost:
rating

<%@ Page Language=”C#” %>

<%@ Register Assembly=”AjaxControlToolkit” Namespace=”AjaxControlToolkit” TagPrefix=”cc1″ %>
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”&gt;

<script runat=“server”>

    protected void Page_Load(object sender, EventArgs e)
    {
        AjaxControlToolkit.Rating rt = new Rating();
        Page.Form.Controls.Add(rt);
        rt.ID = “LikeRating”;
        rt.MaxRating = 5;
        rt.CurrentRating = 2;
        rt.StarCssClass = “ratingStar”;
        rt.WaitingStarCssClass = “savedRatingStar”;
        rt.FilledStarCssClass = “filledRatingStar”;
        rt.EmptyStarCssClass = “emptyRatingStar”;
    }
</script>

<html xmlns=http://www.w3.org/1999/xhtml&#8221;>
<head runat=“server”>
    <title></title>
    <style type=“text/css”>
        /* Rating */.ratingStar
        {
            fontsize: 0pt;
            width: 13px;
            height: 12px;
            margin: 0px;
            padding: 0px;
            cursor: pointer;
            display: block;
            backgroundrepeat: norepeat;
        }
        .filledRatingStar
        {
            backgroundimage: url(Images/FilledStar.png);
        }
        .emptyRatingStar
        {
            backgroundimage: url(Images/EmptyStar.png);
        }
        .savedRatingStar
        {
            backgroundimage: url(Images/SavedStar.png);
        }
    </style>
</head>
<body>
    <form id=“form1” runat=“server”>
    <cc1:ToolkitScriptManager ID=“ToolkitScriptManager1” runat=“server”>
    </cc1:ToolkitScriptManager>
    <div>
    </div>
    <asp:Button ID=“Button1” runat=“server” Text=“Button” />
    </form>
    <p>
        &nbsp;</p>
</body>
</html>


Reason

The problem is because we cannot create the Rating control in the Page_Load, just as we create other server-side controls (for example, TextBox, and so on) in code-behind. the Rating control must be created in Page_Init if we need ViewState to save its status across the PostBack.

Solution 1:

We can create the Rating control in Page_Init:

<%@ Page Language=”C#” %><%@ Register Assembly=”AjaxControlToolkit” Namespace=”AjaxControlToolkit” TagPrefix=”cc1″ %>
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”&gt;<script runat=“server”>void Page_Init(object sender, EventArgs e)
    {
        AjaxControlToolkit.Rating rt = new Rating();
        Page.Form.Controls.Add(rt);
        rt.ID = “LikeRating”;
        rt.MaxRating = 5;
        rt.CurrentRating = 2;
        rt.StarCssClass = “ratingStar”;
        rt.WaitingStarCssClass = “savedRatingStar”;
        rt.FilledStarCssClass = “filledRatingStar”;
        rt.EmptyStarCssClass = “emptyRatingStar”;
    }
</script><html xmlns=http://www.w3.org/1999/xhtml&#8221;>
<head runat=“server”>
    <title></title>
    <style type=“text/css”>
        /* Rating */.ratingStar
        {
            fontsize: 0pt;
            width: 13px;
            height: 12px;
            margin: 0px;
            padding: 0px;
            cursor: pointer;
            display: block;
            backgroundrepeat: norepeat;
        }
        .filledRatingStar
        {
            backgroundimage: url(Images/FilledStar.png);
        }
        .emptyRatingStar
        {
            backgroundimage: url(Images/EmptyStar.png);
        }
        .savedRatingStar
        {
            backgroundimage: url(Images/SavedStar.png);
        }
    </style>
</head>
<body>
    <form id=“form1” runat=“server”>
    <cc1:ToolkitScriptManager ID=“ToolkitScriptManager1” runat=“server”>
    </cc1:ToolkitScriptManager>
    <div>
    </div>
    <asp:Button ID=“Button1” runat=“server” Text=“Button” />
    </form>
    <p>
        &nbsp;</p>
</body>
</html>

Solution 2:

we can use Hidden Field to save the state of Rating control:

Note: We need to set up the Rating control’s BehaviorID, in order to call the Rating’s js interface in JavaScript

<%@ Page Language=”C#” %>
<%@ Register Assembly=”AjaxControlToolkit” Namespace=”AjaxControlToolkit” TagPrefix=”cc1″ %>
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”&gt;<script runat=“server”>void Page_Load(object sender, EventArgs e)
    {
        AjaxControlToolkit.Rating rt = new Rating();
        Panel1.Controls.Add(rt);
        rt.ID = “LikeRating”;
        rt.MaxRating = 5;
        rt.CurrentRating = 2;
        rt.StarCssClass = “ratingStar”;
        rt.WaitingStarCssClass = “savedRatingStar”;
        rt.FilledStarCssClass = “filledRatingStar”;
        rt.EmptyStarCssClass = “emptyRatingStar”;
        rt.BehaviorID = “hichange”;
        rt.CurrentRating = Convert.ToInt32(this.Hidden1.Value);
    }
   
</script><html xmlns=http://www.w3.org/1999/xhtml&#8221;>
<head runat=“server”>
    <title></title>
    <style type=“text/css”>
        /* Rating */.ratingStar
        {
            fontsize: 0pt;
            width: 13px;
            height: 12px;
            margin: 0px;
            padding: 0px;
            cursor: pointer;
            display: block;
            backgroundrepeat: norepeat;
        }
        .filledRatingStar
        {
            backgroundimage: url(Images/FilledStar.png);
        }
        .emptyRatingStar
        {
            backgroundimage: url(Images/EmptyStar.png);
        }
        .savedRatingStar
        {
            backgroundimage: url(Images/SavedStar.png);
        }
    </style>
   
    <script type=“text/javascript”>function save_rate() {
            var state = $find(“hichange”).get_Rating();
            $get(“Hidden1”).value = state;
            alert(state);
        }
   
    </script>
</head>
<body>
    <form id=“form1” runat=“server”>
    <cc1:ToolkitScriptManager ID=“ToolkitScriptManager1” runat=“server”>
    </cc1:ToolkitScriptManager>
    <asp:Panel ID=“Panel1” runat=“server” onclick=“save_rate();”>
    </asp:Panel>
    <asp:Button ID=“Button1” runat=“server” Text=“Button” />
    <input id=“Hidden1” runat=“server” type=“hidden” value=“1” />
    <p>
        &nbsp;</p>
    </form>
    </body>
</html>

November 10, 2008 Posted by | ASP.NET AJAX, ASP.NET AJAX Advance Tips & Tricks | | 1 Comment

Change the icon of ValidatorCalloutExtender

We can use the WarningIconImageUrl=”me.jpg” to achieve the facing goal:
 
 

<%@ Page Language=”C#” %>

<%@ Register Assembly=”AjaxControlToolkit” Namespace=”AjaxControlToolkit” TagPrefix=”cc1″ %>
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”&gt;

<script runat=“server”>

</script>

<html xmlns=http://www.w3.org/1999/xhtml&#8221;>
<head runat=“server”>
    <title></title>
</head>
<body>
    <form id=“form1” runat=“server”>
    <div>
        <cc1:ToolkitScriptManager ID=“ToolkitScriptManager1” runat=“server”>
        </cc1:ToolkitScriptManager>
        <asp:TextBox ID=“TextBox1” runat=“server”></asp:TextBox>
        <asp:RequiredFieldValidator ID=“RequiredFieldValidator1” Display=“None” runat=“server”
            ControlToValidate=“TextBox1” ErrorMessage=“RequiredFieldValidator”></asp:RequiredFieldValidator>
        <cc1:ValidatorCalloutExtender ID=“RequiredFieldValidator1_ValidatorCalloutExtender”
            runat=“server” Enabled=“True” TargetControlID=“RequiredFieldValidator1” WarningIconImageUrl=“me.jpg”>
        </cc1:ValidatorCalloutExtender>
    </div>
    <asp:Button ID=“Button1” runat=“server” Text=“Button” />
    </form>
</body>
</html>

October 31, 2008 Posted by | ASP.NET AJAX | | Leave a comment

MaskedEdit date for dd-MMM-yyyy

Please try the following code:

 

 

<%@ Page Language=”C#” %>

<%@ Register Assembly=”AjaxControlToolkit” Namespace=”AjaxControlToolkit” TagPrefix=”ajaxToolkit” %>

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”&gt;

<script runat=“server”>

</script>

<html xmlns=http://www.w3.org/1999/xhtml&#8221;>
<head runat=“server”>
    <title></title>
</head>
<body>
    <form id=“form1” runat=“server”>
    <div>
    <div>
        <ajaxToolkit:ToolkitScriptManager ID=“ToolkitScriptManager1” runat=“server”>
        </ajaxToolkit:ToolkitScriptManager>
        <strong>Enter Date (format:dd-MMM-yyyy <em>dd-MMM-yyyy</em>):</strong>
        <br />
        <asp:TextBox ID=“TextBox2” runat=“server” ReadOnly=“false” />
        <ajaxToolkit:MaskedEditExtender ID=“MaskedEditExtender2” runat=“server” ClearMaskOnLostFocus=“false”
            MaskType=“none” Mask=“99-LLL-9999” TargetControlID=“TextBox2” Filtered=“-“ />
        <ajaxToolkit:MaskedEditValidator ID=“MaskedEditValidator2” runat=“server” ControlToValidate=“TextBox2”
            ControlExtender=“MaskedEditExtender2” EmptyValueMessage=“Start Date is Required”
            InvalidValueMessage=“Date is Invalid” IsValidEmpty=“False” TooltipMessage=“Input a Date”
            Enabled=“true” />
        <ajaxToolkit:CalendarExtender ID=“CalendarExtender3” runat=“server” TargetControlID=“TextBox2”
            Format=“dd-MMM-yyyy” PopupButtonID=“ImageButton2” />
    </div>
    </div>
    </form>
</body>
</html>

October 31, 2008 Posted by | ASP.NET AJAX | | Leave a comment

Make postback from ModalPopupExtender

To make a button which inside ModalPopup do a server-side onclick event, we should make sure the OkControlID of the ModalPopup is not the button we want to do a postback:

<%@ Page Language=”C#” %>
<%@ Register Assembly=”AjaxControlToolkit” Namespace=”AjaxControlToolkit” TagPrefix=”cc1″ %>
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”&gt;

<script runat=“server”>
protected void btn_OK_Click(object sender, EventArgs e)
{
Page.Title = “lance”;
}

</script>

<html xmlns=http://www.w3.org/1999/xhtml&#8221;>
<head runat=“server”>
<title></title>
</head>
<body>
<form id=“form1” runat=“server”>
<div>
<asp:LinkButton ID=“lnkbtn_comments” runat=“server”>LinkButton</asp:LinkButton>
<cc1:ToolkitScriptManager ID=“ToolkitScriptManager1” runat=“server”>
</cc1:ToolkitScriptManager>
<asp:Panel ID=“panel_Comment” runat=“server” Width=“300px” Height=“150px” CssClass=“modalPopup”>
<br />
<br />
<center>
<table>
<tr>
<td>
Title:
</td>
<td align=“left”>
<asp:TextBox ID=“txt_Title” runat=“server” />
</td>
</tr>
<tr>
<td>
Comment:
</td>
<td>
<asp:TextBox ID=“txt_Comment” runat=“server” TextMode=“MultiLine” />
</td>
</tr>
<tr>
<td>
<asp:Button ID=“btn_OK” runat=“server” Text=“Save” OnClick=“btn_OK_Click” />
</td>
<td align=“left”>
<asp:Button ID=“btn_Cancel” runat=“server” Text=“Cancel” />
</td>
</tr>
</table>
</center>
</asp:Panel>
<cc1:ModalPopupExtender ID=“panel_Comment_ModalPopupExtender” runat=“server” TargetControlID=“lnkbtn_comments”
PopupControlID=“panel_Comment” DropShadow=“true” BackgroundCssClass=“modalBackground”
CancelControlID=“btn_Cancel”>
</cc1:ModalPopupExtender>
</div>
</form>
</body>
</html>

October 31, 2008 Posted by | ASP.NET AJAX | | 1 Comment