Building Interactive User Interfaces with Microsoft ASP.NET AJAX: Enabling Bookmarking and the Browser's Back ButtonBy Scott Mitchell
The good news is that starting with ASP.NET 3.5 SP 1, the ScriptManager control in the ASP.NET AJAX Framework includes functionality for creating history points in an AJAX-enabled web page. Adding a history point creates an entry in the browser's history for a particular page state. What's more, this page state is encoded in the querystring of the browser, meaning that visitors can bookmark a particular state of an AJAX application.
This article shows how to add history points using the ScriptManager control. In particular, it shows how to record history points whenever the user pages or sorts a GridView. Read on to learn more!
A Quick Overview of the ASP.NET AJAX History Feature
As noted in the Introduction, the history feature became part of the ASP.NET AJAX Framework in ASP.NET version 3.5, SP 1. (For a link to download SP1, and for more information on the features included in SP1, see: ASP.NET in .NET 3.5 Service Pack 1.) It was originally part of the Microsoft ASP.NET Futures, although at that point in time this functionality was implemented using a History Web control. In the ASP.NET 3.5 SP1 release, this functionality was moved to the ScriptManager control.
|You Will Need ASP.NET 3.5 SP1 to Run the Demo|
|Each installment of this article series has included a demo available for download. This installment is no different. However, the previous installments worked with ASP.NET version 2.0 and up. Because this installment's demo uses features only found in ASP.NET 3.5 SP1 it only works with that version of ASP.NET and beyond. If you do not have ASP.NET 3.5 SP1 installed, you can download the free Visual Web Developer 2008 and use it for running this article's demo. The Visual Web Developer installation will install the appropriate framework version for you, if needed.|
The ASP.NET AJAX history feature works in the following manner:
- You, the page developer, decide what actions are cause for a history point to be added. These actions can be client-side actions (clicking on an HTML element) or server-side actions triggered by a partial page postback. The set of actions that should cause a history point depend on the web page and its user interface. The download available at the end of this article includes two pages that display a sortable and page-able GridView. In one page, each sort action causes the insertion of a history point; in the other, both sorting and paging actions cause the insertion of a history point.
- When an action that should cause the insertion of a history point fires, you need to add a history point. This is done by creating some
string that models the state and registering that history state with the ScriptManager control. You can also update the page's
Titlebased on the state so that the browser's title bar and history information includes an apt description for each state.
- Finally, you need to create an event handler for the ScriptManager's
Navigateevent. This event fires whenever the user reaches the page by clicking the Back or Forward buttons or when coming in from a bookmark. The
Navigateevent handler is responsible for restoring the history state.
The remainder of this article looks at how to save a history point whenever a GridView is sorted, and how to restore that state when needed. Let's get started!
Paging and Sorting Through Products in an AJAX-Enabled Web Page
Before we concern ourselves with ASP.NET AJAX's history feature, let's start by creating and demonstrating the standard AJAX behavior with regard to the Back button and bookmarks. The demo available for download at the end of this article includes an ASP.NET page named
StandardBehavior.aspxthat contains a sortable and page-able GridView that lists the contents of the
Productstable in the Northwind database. The GridView is placed within an UpdatePanel and therefore any postbacks triggered by the GridView are handled as partial page postbacks.
In addition to the UpdatePanel and GridView, the page includes a ScriptManager control. As discussed in the first installment of this article series, AJAX Basics and Getting Started with Microsoft's ASP.NET AJAX Framework, the ScriptManager control must be on any page that uses the ASP.NET AJAX framework, as it serves as the plumbing between the client-side and server-side aspects of an AJAX-enabled web page. As we'll see shortly, the ScriptManager control also is key in adding history points and restoring prior state.
StandardBehavior.aspx and sort and page through the grid. Each time a sort or paging link is clicked, a partial page postback
ensues and the grid's display is updated. Because partial page postbacks are used, the browser does not maintain any sort of history when sorting
and paging. Therefore, if you click the Back button you will not be taken back to the previous sort order or the previous page. Instead, you'll be
returned to the page you were visiting before you reached the
StandardBehavior.aspx page. The following screen shots illustrate
Start by Visiting
Click on the "Behavior With History on Sorting" Link. Now Sort and Page through the Grid Several Times. Here is the Grid After I've Sorted by Price and Moved to Page 4...
Click Your Browser's Back Button. You are Returned to
Adding a History Point Whenever the User Sorts the Grid
Let's extend our example to save a history point whenever the user sorts the grid. By doing so, each time the user sorts the grid the browser will record a new history state and the browser's URL will have its querystring updated to include the state information (this allows the page to be bookmarked). With recording history points whenever the grid is sorted, the user could sort the grid by Price, then by Name, and then by ProductID. If the user, while viewing the grid sorted by ProductID, clicked his browser's Back button, he would be returned to seeing the grid sorted by Name (rather than being returned to the page visited prior to reaching this page). The demo available for download at the end of this article includes an ASP.NET page named
BehaviorWithHistory.aspxthat implements this functionality.
Recall earlier that I said there are three things we need to do when using the ASP.NET AJAX history feature:
- Decide what actions cause a history point to be inserted.
- Add the history point whenever one of the actions from task #1 is performed.
- Create an event handler for the ScriptManager's
Navigateevent that restores the state when the user clicks the Back or Forward buttons, or when he reaches a page via a bookmark.
Sortingevent. We need to create an event handler for the
Sortingevent to add a history point.
A history point is added via a call to the ScriptManager class's
method. This method requires that we supply a string that describes the current state. This string will be used later in the ScriptManager's
Navigate event handler to reconstruct the state of the application when a page is reached via the Back or Forward buttons, or from
a bookmark. Because we are basing the history point on the sort criteria, the GridView's
properties define the state. Therefore, we need to pass the values of these properties into the
The following code shows how I encode the GridView's state and add it as a history point.
Note that for each item I want to store in the state I call the
AddHistoryPoint method, passing in a "name" for the state item and
its value. In the above code I register two items in the state, named "SortExpression" and "SortDirection" and storing the values of
After saving the state, I update the page's title. The GetPageTitle method generates and returns a suitable title given the passed-in
SortDirection values. For instance, when sorting by the
UnitPrice column in ascending order the
GetPageTitle method returns the string "Viewing Products Sorted by Price (Ascending)". This value is assigned to the
Title property. (For more information on how to set an ASP.NET page's title programmatically, see
Dynamically Setting the Page's Title.
If we visit the page with this code in place, each time we sort the grid the URL in the browser's Address bar is updated to include a querystring
that specifies the state information. Note the Address bar in the following screen shots. When the
BehaviorWithHistory.aspx page is first
visited the URL is, as we'd expect, just
But as soon as the grid is sorted the querystring is updated to include the encoded state information. Also the Back button is now available.
In the screen shot below the grid is sorted by Price in ascending order and the URL in the Address bar now reads:
While the Back button is now click-able, going back does not return us to the previous state of the grid before it was sorted by Price. Rather, we
remain on the
BehaviorWithHistory.aspx page, but the data is still sorted by Price. This is because we have yet to complete the final step
- task #3 - which is to create an event handler for the ScriptManager control's
Navigate event. The
Navigate event handler
fires whenever the user visits a page by clicking the Back or Forward buttons or via a bookmark. The
Navigate event handler is responsible
for rendering the state as specified through the querystring.
Navigate event handler starts by checking to see if the expected state was passed in. If so, it grabs the values from the
history state (via
e.State), sorts the GridView, and updates the page's title. If the state information was not passed in, it
defaults to the default state - the grid sorted by the
ProductName column in ascending order.
That's all there is to it! With this code in place, the Back and Forward buttons work as expected. What's more, a user can bookmark the web page after sorting by a particular column. When the user returns to that bookmarked page, the GridView will load and automatically sort by the appropriate column.
What About Paging?
BehaviorWithHistory.aspxpage adds a history point whenever the user sorts the grid. It does not, however, add a history point when paging. If a user sorts the grid by, say, Price, the querystring is updated to reflect the state information. If they then go to page 2 in the grid the the querystring is not updated and no entry is added to the browser's history. If at this point they hit the Back button, they are not returned to page 1, sorted by Price. Instead, they are returned to the grid prior to sorting it by Price. Likewise, if a user sorts the grid by Price, navigates to page 5, and adds a bookmark to their browser, if they later visit that bookmark the screen will load the grid sorted by Price, but will show page 1 of the data.
If you want to add a history point whenever the grid is sorted or paged, then you'll need to record the GridView's
as an additional history state item in the
Sorting event handler. You'll also need to create an event handler for the GridView's
PageIndexChanging event, which fires whenever the user navigates to a new page. In this event handler you'll need to add a history point,
recording the sort- and paging-related properties. Finally, you'll need to update the ScriptManager's
Navigate event handler to set
PageIndex property to the value stored in the history state.
The download includes a complete, working example of a GridView that records history points whenever it is sorted or pages. See the
BehaviorWithHistory2.aspx ASP.NET page.
Because AJAX-enabled web pages circumvent the standard browser request/form submission model, partial page postbacks do not register as new entries in the browser's history. This behavior neuters the usefulness of the browser's Back and Forward buttons, as well as bookmarks. The good news is that the ASP.NET AJAX framework, starting with ASP.NET 3.5 SP1, includes functionality to record history points. Recording a history point saves the state that describes the history in the querystring and adds an entry to the browser's history. This enables visitors to use their browsers' Back and Forward buttons to navigate through different states in an AJAX-enabled web page. It also allows for bookmarking of different states in an AJAX-enabled application.