As
you've learned, the UpdatePanel performs its work asynchronously in the
background. As a result, the user can keep working with the page. This
is generally the behavior you want, but there's one catch. While the
asynchronous request is under way, the user won't necessarily realize
that anything's happening. If the asynchronous request takes some time,
this could be a bit of a problem. At worst, the user will assume the
page is broken or click the same button multiple times, creating
needless extra work for your web application and slowing down the
process further.
ASP.NET includes another
control that can help—the UpdateProgress control. The UpdateProgress
control works in conjunction with the UpdatePanel. Essentially, the
UpdateProgress control allows you to show a message while a
time-consuming update is under way.
NOTE
The UpdateProgress
control is slightly misnamed. It doesn't actually indicate progress;
instead, it provides a wait message that reassures the user that the
page is still working and the last request is still being processed.
1. Showing a Simulated Progress Bar
When you add the
UpdateProgress control to a page, you get the ability to specify some
content that will appear as soon as an asynchronous request is started
and disappear as soon as the request is finished. This content can
include a fixed message, but many people prefer to use an animated GIF,
because it more clearly suggests that the page is still at work. Often,
this animated GIF simulates a progress bar.
The top figure shows the page as it first
appears, with a straightforward UpdatePanel control containing a button.
When the button is clicked, the asynchronous callback process begins.
At this point, the contents of the UpdateProgress control appear
underneath (as shown in the middle figure). In this example, the
UpdateProgress includes a text message and an animated GIF that appears
as a progress bar, with green blocks that perpetually fill it from left
to right, and then start over. When the callback is complete, the
UpdateProgress disappears and the UpdatePanel is updated, as shown in
the bottom figure.
The markup for this page defines an UpdatePanel followed by an UpdateProgress:
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<div style="background-color:#FFFFE0;padding: 20px">
<asp:Label ID="lblTime" runat="server" Font-Bold="True"></asp:Label>
<br /><br />
<asp:Button ID="cmdRefreshTime" runat="server"
Text="Start the Refresh Process" />
</div>
</ContentTemplate>
</asp:UpdatePanel>
<br />
<asp:UpdateProgress ID="updateProgress1" runat="server">
<ProgressTemplate>
<div style="font-size: xx-small">
Contacting Server ... <img src="wait.gif" alt="Waiting..." />
</div>
</ProgressTemplate>
</asp:UpdateProgress>
This isn't the only possible
arrangement. Depending on the layout you want, you can place your
UpdateProgress control somewhere inside your UpdatePanel control.
The code for this page has a
slight modification from the earlier examples. Because the
UpdateProgress control only shows its content while the asynchronous
callback is under way, it only makes sense to use it with an operation
that takes time. Otherwise, the UpdateProgress will only show its
ProgressTemplate for a few fractions of a second. To simulate a slow
process, you can add a line to delay your code 10 seconds, as shown
here:
Protected Sub cmdRefreshTime_Click(ByVal sender As Object, _
ByVal e As EventArgs) Handles cmdRefreshTime.Click
System.Threading.Thread.Sleep(TimeSpan.FromSeconds(10))
lblTime.Text = DateTime.Now.ToLongTimeString()
End Sub
There's no need to explicitly
link the UpdateProgress control to your UpdatePanel control. The
UpdateProgress automatically shows its ProgressTemplate whenever any
UpdatePanel begins a callback. However, if you have a complex page with
more than one UpdatePanel, you can choose to limit your UpdateProgress
to pay attention to just one of them. To do so, simply set the
UpdateProgress.AssociatedUpdatePanelID property with the ID of the
appropriate UpdatePanel. You can even add multiple UpdateProgress
controls to the same page, and link each one to a different UpdatePanel.
2. Cancellation
The UpdateProgress
control supports one other detail: a cancel button. When the user clicks
a cancel button, the asynchronous callback will be cancelled
immediately, the UpdateProgress content will disappear, and the page
will revert to its original state.
Adding a cancel button is a
two-step process. First you need to add a fairly intimidating block of
JavaScript code, which you can copy verbatim. You should place this code
at the end of your page, after all your content but just before the
</body> end tag. Here's the code you need, in its rightful place:
<%@ Page Language="VB" AutoEventWireup="false" CodeFile="WaitIndicator.aspx.vb"
Inherits="WaitIndicator" %>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
...
</head>
<body>
<form ID="form1" runat="server">
...
</form>
<script type="text/javascript">
var prm = Sys.WebForms.PageRequestManager.getInstance();
prm.add_initializeRequest(InitializeRequest);
function InitializeRequest(sender, args)
{
if (prm.get_isInAsyncPostBack())
{
args.set_cancel(true);
}
}
function AbortPostBack()
{
if (prm.get_isInAsyncPostBack()) {
prm.abortPostBack();
}
}
</script>
</body>
</html>
Once you've added this code,
you can use JavaScript code to call its AbortPostBack() function at any
time and cancel the callback. The easiest way to do to this is to
connect a JavaScript event to the AbortPostBack() function using a
JavaScript event attribute. You can add a JavaScript event attribute to
virtually any HTML element. For example, you can deal with client-side
clicks using the onclick attribute. Here's a basic HTML button (not a
server control) that uses this technique to connect itself to the
AbortPostBack() function:
<input ID="cmdCancel" onclick="AbortPostBack()" type="button" value="Cancel" />
If you click this Cancel
button, the client-side AbortPostBack() function will be triggered and
the callback will be cancelled immediately. Typically, you'll place this
button (or an element like this) in the ProgressTemplate of the
UpdateProgress control, as shown in Figure 1.
Don't confuse this approach with
server-side event handling—the client-side onclick attribute allows you
to intercept an event in the browser and process it using JavaScript
code. The server doesn't get involved at all. In fact, when you cancel
an operation, the server continues to process the request, but the
browser simply closes the connection and stops listening for the
response.
It makes sense to use an
abort button for tasks that can be safely canceled because they don't
change external state. For example, users should be able to cancel an
operation that retrieves information from a database. However, it's not a
good idea to add cancellation to an operation that updates a database,
because the server will continue until it finishes the update, even if
the client has stopped listening for the response.
|
|