(How)
C^# You Are - 19 August 2007
ASP.NET and AJAX is the focus this week.
- How is ScriptManager different than ClientScriptManager? Answer
ClientScriptManager is the script management class for ASP.NET.
It provides a consistent mechanism for adding client-side scripting blocks and registering
startup scripts. Unfortunately it does not handle callbacks properly.
ScriptManager is the AJAX replacement. It handles all the
functionality of ClientScriptManager and is callback aware such
that scripts can be inserted and manipulated outside the normal callback.
For all future code use ScriptManager in lieu of ClientScriptManager.
ScriptManager exposes the same API as ClientScriptManager
so a global search and replace will work well. One note of interest.
ScriptManager is a control. It must be added to any page
that wants to take advantage of AJAX.
- What is the difference between a callback and a partial postback (or page rendering)? Answer
The only real difference is the terminology but when people are using these terms
they generally have two different concepts in mind. A callback occurs when
the client calls back to the server to perform some work and then updates the UI
on the client. It is different than a normal postback because only the necessary
UI elements are updated.
A partial postback is the AJAX terminology for a callback. In reality a partial
postback uses a callback to call back into the server. Callbacks are supported
in ASP.NET v2 but not partial postbacks. AJAX adds support for partial postbacks.
With partial postbacks AJAX effectively takes over the rendering of the page.
When a partial postback occurs AJAX steps in lets ASP.NET start the normal postback
process. However AJAX controls the rendering so it only renders the controls
that it needs. When rendering is complete AJAX packages up the rendered data
and returns it to the client. On the client-side AJAX updates the DOM for
the page with the changes.
- How can you detect a partial postback? Answer
ScriptManager exposes the property IsInAsyncPostBack
to specify whether a partial postback is occurring. You should use this property
to determine whether you should do any work during a partial postback. It
works similar to how IsPostBack works.
- How can you set the focus to a control in ASP.NET? Answer
Surprisingly ASP.NET does not expose any functionality to do this. Traditionally
you would do it using some custom client-side code. With AJAX ScriptManager
exposes the SetFocus method that you can use to set the focus to
a control when it is loaded.
- What does the UpdatePanel do? Answer
The UpdatePanel control is the key to AJAX's success. Use
UpdatePanel to group controls together that should be updated when
a partial postback occurs. This control is similar to a regular Panel
control. So how does it work? It is a little complicated so
I recommend you go read about it in the AJAX documentation. Nevertheless the
concept is straightforward. AJAX hooks into any postback requests of the control.
When AJAX detects a postback on the client it packages it up as a callback and sends
it to the server. On the server AJAX detects the callback, renders as a partial
postback and sends the response back. On the client AJAX takes apart the results
and updates the DOM for the page. Only the controls within the panel (and
a few exceptions) are updated.
A page can contain any number of UpdatePanels. Use multiple
panels to separate out controls on the page. Each panel can be updated separately
allowing you to partially render only the controls that should be changed. As
a side note an UpdatePanel can update under certain other circumstances
as well. Refer to the UpdatePanel document and Triggers
and UpdateMode properties for more examples. In the case
of multiple panels be sure to set UpdateMode to Conditional
to prevent all the panels from updating at once.
- How do you update a control outside an UpdatePanel? Answer
Occasionally you need to update a control that does not reside in an UpdatePanel
yet is impacted by changes in the controls within the panel. For example a
shopping cart might be within a panel to allow partial rendering and yet the total
might reside outside the panel. To cause AJAX to update a control outside
the panel use the RegisterDataItem method on the ScriptManager
class. You would call this method during the partial rendering on the server.
You specify the control to update and the string data to send to it. On the
client you would create a script that handles the load event of the page, grabs
the data from AJAX and updates the control contents.
Here is a simple example where the data and time is displayed at the top of the
page each time it is partially rendered. When the button is clicked it posts
back to the server (partially) and stalls for 1 second. Meanwhile the label
is registered with AJAX to update to the latest time. When the page finishes
its rendering the page handler is invoked (on the client) to update the label.
<%@ Page Language="C#" AutoEventWireup="true" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<script runat="server">
protected void Page_Load (object sender, EventArgs e)
{
if (!IsPostBack)
lblTime.Text = DateTime.Now.ToString();
if (ScriptManager1.IsInAsyncPostBack)
ScriptManager1.RegisterDataItem(lblTime, DateTime.Now.ToString());
}
protected void Button1_Click ( object sender, EventArgs e )
{
System.Threading.Thread.Sleep(1000);
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server" />
Time: <asp:Label ID="lblTime" runat="server" Text="Label"></asp:Label>
<div>
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Button" />
</ContentTemplate>
</asp:UpdatePanel>
</div>
<script language="javascript" type="text/javascript">
Sys.WebForms.PageRequestManager.getInstance().add_pageLoading(OnPageLoad);
function OnPageLoad ( sender, e )
{
var data = e.get_dataItems();
if ($get('lblTime') != null)
$get('lblTime').innerHTML = data["lblTime"];
}
</script>
</form>
</body>
</html>
- What does the Timer control in AJAX do? Answer
.NET ships with three different timers: thread-based (System.Threading.Timer),
server-app (System.Timers.Timer) and WinForms (System.Windows.Forms.Timer).
AJAX adds yet another (System.Web.UI.Timer). The AJAX timer
is client-based. This allows the page to periodically update itself without
having to write any code. For example a stock watching site might update the
table of stock prices every 5 seconds. The AJAX timer uses partial rendering
to call back to the server. It uses the underlying Javascript functionality
for this.
The following example is the same as above except we removed the button and its
handler and dropped in Timer instead. The timer fires every
5 seconds to update the time. In this example we put the timer inside the
UpdatePanel but this is not required.
<%@ Page Language="C#" AutoEventWireup="true" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<script runat="server">
protected void Page_Load (object sender, EventArgs e)
{
if (!IsPostBack)
lblTime.Text = DateTime.Now.ToString();
if (ScriptManager1.IsInAsyncPostBack)
ScriptManager1.RegisterDataItem(lblTime, DateTime.Now.ToString());
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server" />
Time: <asp:Label ID="lblTime" runat="server" Text="Label"></asp:Label>
<div>
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<asp:Timer ID="Timer1" runat="server" Interval="5000"></asp:Timer>
</ContentTemplate>
</asp:UpdatePanel>
</div>
<script language="javascript" type="text/javascript">
Sys.WebForms.PageRequestManager.getInstance().add_pageLoading(OnPageLoad);
function OnPageLoad ( sender, e )
{
var data = e.get_dataItems();
if ($get('lblTime') != null)
$get('lblTime').innerHTML = data["lblTime"];
}
</script>
</form>
</body>
</html>
- What is a trigger on an UpdatePanel? Answer
Sometimes you want a panel to update only when a certain event occurs. This
is where triggers enter. A trigger causes the panel to do a partial render.
Normally the child controls of a panel cause the partial rendering when they postback
but controls outside the panel can do so as well. Using a trigger you can
configure a panel to update when a control (outside the panel) tries to postback.
This is useful because it does not make a lot of sense to put a button (which shouldn't
change across renderings) inside a panel just to allow a partial rendering to occur.
Taking the example from earlier we move the time label inside the update panel (so
we can remove the client-side script to update it). We put a button outside
the panel to update the time. On the server whenever the button is clicked
the label is updated. Since it is inside an UpdatePanel it
will be refreshed on the client. However since the button is not inside the
panel we have to tell the panel to partially render whenever the button is clicked.
<%@ Page Language="C#" AutoEventWireup="true" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<script runat="server">
protected void Page_Load (object sender, EventArgs e)
{
if (!IsPostBack)
lblTime.Text = DateTime.Now.ToString();
}
protected void Button1_Clicked ( object sender, EventArgs e )
{
lblTime.Text = DateTime.Now.ToString();
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server" />
<div>
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
Time: <asp:Label
ID="lblTime" runat="server" Text="Label"></asp:Label>
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="button1"/>
</Triggers>
</asp:UpdatePanel>
</div>
<asp:Button id="button1" runat="server" OnClick="Button1_Clicked"
Text="Update"/>
</form>
</body>
</html>