使用 ASP.NET 服务器控件管理浏览器历史记录

更新:2007 年 11 月

作为页面开发人员,您可以使用 ScriptManagerScriptManagerProxy 这两个服务器控件来管理浏览器历史记录项和提供逻辑导航。ScriptManager 服务器控件用于在应用程序中设置历史时间点。使用这两个控件可以处理在由于某个历史记录状态的结果而请求网页时发生的导航。

历史时间点是 Web 应用程序中的逻辑导航点,可以通过状态信息来表示。状态信息可用于将 Web 应用程序还原到以前的状态,此操作既可以直接用状态数据来实现,也可以通过一个存储在其他地方的状态信息标识符来实现。

历史时间点仅以 URL 的形式存储在浏览器的历史记录堆栈中。历史记录状态以查询字符串中的数据的形式来管理,或者以带有“#”字符标记的 URL 片段值的形式来管理。由于 URL 的大小限制,必须创建尽可能小的状态信息。下面的示例演示一个包含足够标识状态的历史时间点数据的 URL。由此,应用程序可以在该状态下重新创建页面。

http://MySamples/Ajax/Default.aspx#&&state=2

用户单击浏览器的**“后退”**按钮之后,浏览器将转到以前查看过的 URL(包括含有历史时间点状态的 URL)。网页中的客户端代码会检测到 URL 包含历史记录状态数据,向页面发出请求,并传递状态信息。页面处理该请求的同时,会读取历史记录状态信息并触发异步回发。然后 ScriptManagerScriptManagerProxy 这两个服务器控件会引发 Navigate 事件。可以处理该事件并根据需要为 Web 应用程序重新创建该页面。

Cc488548.alert_note(zh-cn,VS.90).gif说明:

要生成本主题中的代码示例,需要 Visual Studio 2008 Service Pack 1 或更高版本。

ScriptManager 和 ScriptManagerProxy 控件语法

下面的示例演示用于处理浏览器历史记录的 ScriptManager 服务器控件的语法。

<asp:ScriptManager runat="server" 
    EnableHistory="true|false"
    EnableStateHash="true|false"
    OnNavigate="navigateEventhandlerName">
</asp:ScriptManager>

启用浏览器历史记录管理

要使用历史记录管理,必须通过 ScriptManager 服务器控件来启用它。默认情况下不启用历史记录支持。启用历史记录后,会针对每个浏览器以相应的方式来实现它。对于 Internet Explorer,会向浏览器呈现一个 iframe 元素,从而导致向服务器发出另一个请求。因此该模型是一种可考虑的方法。下面的示例演示如何通过 ScriptManager 控件以声明方式启用历史记录。

<asp:ScriptManager runat="server" ID="ScriptManager1" 
    EnableHistory="true" />

创建浏览器历史时间点

要创建浏览器历史时间点,请调用 ScriptManager 控件的 AddHistoryPoint 方法。此方法使您可以定义服务器状态和键,并可以选择定义数据来表示浏览器中历史记录项的标题。在引发后续的历史记录导航事件后,可以使用状态数据重新创建页面的状态。创建历史时间点时,默认情况下,序列化和加密后的数据会追加到网页 URL 的后面。最后生成的 URL 包括在浏览器的历史记录堆栈中。

Cc488548.alert_note(zh-cn,VS.90).gif说明:

只有在响应用户操作(例如单击某个选项)时才添加历史时间点。通常,仅仅运行应用程序代码并不会添加历史时间点。

下面的示例使用 UpdatePanel 控件在页面上启动异步回发。在触发异步回发的按钮的 Click 事件处理程序期间,使用 ScriptManager 控件来添加历史时间点。单击浏览器的**“后退”**按钮时,不会离开网页,而是导航页面以前的历史记录状态。

运行此功能的示例。

<%@ Page Language="VB" %>
<%@ Import Namespace="System.Globalization" %>
<%@ Import Namespace="System.Collections.Generic" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">
    Private Shared key As String = "s"

    ' Handle the Navigate event
    Public Sub OnNavigateHistory(ByVal sender As Object, ByVal e As HistoryEventArgs)
        LabelHistoryData.Text = Server.HtmlEncode(e.State(key))
    End Sub

    ' On button click, handle the event and set a history point. 
    Public Sub ButtonClick(ByVal sender As Object, ByVal e As EventArgs)
        LabelHistoryData.Text = CType(sender, Button).Text
        ScriptManager.GetCurrent(Me).AddHistoryPoint(key, LabelHistoryData.Text)
    End Sub
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
    <title>Microsoft ASP.NET 3.5 Extensions: Managing History</title>
    <link href="../../include/qsstyle.css" type="text/css" rel="Stylesheet" />
</head>
<body>
    <form id="form1" runat="server">
        <div>
            <asp:ScriptManager runat="server" ID="ScriptManager1" OnNavigate="OnNavigateHistory" 
                EnableHistory="true" EnableSecureHistoryState="false" />
            <h2>
                Microsoft ASP.NET 3.5 Extensions: Adding Server-side Browser History Points</h2>
            <p/>

            <div id="Div1" class="new">
                <p>This sample shows:</p>
                <ol>
                    <li>How to use the <code>ScriptManager</code> control to set a history point.</li>
                    <li>The <code>ScriptManager</code> control, the <code>EnableHistory</code> and 
                    <code>EnableSecureHistoryState</code> properties and 
                    the <code>OnNavigate</code> property to handle the <code>navigate</code>event.<br />
                    </li>
                </ol>
            </div>

            <p>
                In this example, three buttons outside the <code>UpdatePanel</code> control can
                trigger an asynchronous postback. You can see the results of the update through
                the date and time that renders in the Web page along with a value indicating the 
                button that triggered the partial refresh.</p>
            <p>
                When you press a button, the server-side <code>Click</code> event handler for the button 
                stores data and uses the data as a history point. If you click the browser's Back button, 
                you will see the state Web page return to a previous button value, representing the previous 
                button you pressed. However, you will see that the time within the Web page continues to be 
                incremented.
            </p>
            <p>To see the effect of this logic, do the following.</p>

            <ol>
                <li>Press <b>1</b>. See the panel refresh.</li>
                <li>Press <b>3</b>. See the panel refresh.</li>
                <li>Press <b>2</b>. See the panel refresh.</li>
                <li>Press the browser's Back button. Note that the panel is refreshed with previous
                    data, but the date and time are updated to current values.</li>
            </ol>
            <asp:UpdatePanel ID="UpdatePanel1" runat="server">
                <Triggers>
                    <asp:AsyncPostBackTrigger ControlID="Button1" EventName="Click" />
                    <asp:AsyncPostBackTrigger ControlID="Button2" EventName="Click" />
                    <asp:AsyncPostBackTrigger ControlID="Button3" EventName="Click" />
                </Triggers>
                <ContentTemplate>
                    <asp:Panel runat="server" CssClass="box" ID="Content" Height="40px">
                        Date and Time:
                        <%= DateTime.Now.ToLongTimeString() %>
                        <br />
                        Page's refresh state:
                        <asp:Label runat="server" ID="LabelHistoryData" />
                    </asp:Panel>
                </ContentTemplate>
            </asp:UpdatePanel>
            <p />
            <asp:Button runat="server" ID="Button1" Text="Key 1" OnClick="ButtonClick" />
            <asp:Button runat="server" ID="Button2" Text="Key 2" OnClick="ButtonClick" />
            <asp:Button runat="server" ID="Button3" Text="Key 3" OnClick="ButtonClick" />
        </div>
    </form>
</body>
</html>
<%@ Page Language="C#" %>
<%@ Import Namespace="System.Globalization" %>
<%@ Import Namespace="System.Collections.Generic" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">
    private static String key = "s";

    // Handle the Navigate event
    public void OnNavigateHistory(object sender, HistoryEventArgs e) {
        LabelHistoryData.Text = Server.HtmlEncode(e.State[key]);
    }

    // On button click, handle the event and set a history point. 
    public void ButtonClick(object sender, EventArgs e) {
        LabelHistoryData.Text = ((Button)sender).Text;
        ScriptManager.GetCurrent(this).AddHistoryPoint(key, LabelHistoryData.Text);
    }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
    <title>Microsoft ASP.NET 3.5 Extensions: Managing History</title>
    <link href="../../include/qsstyle.css" type="text/css" rel="Stylesheet" />
</head>
<body>
    <form id="form1" runat="server">
        <div>
            <asp:ScriptManager runat="server" ID="ScriptManager1" OnNavigate="OnNavigateHistory" 
                EnableHistory="true" EnableSecureHistoryState="false" />
            <h2>
                Microsoft ASP.NET 3.5 Extensions: Adding Server-side Browser History Points</h2>
            <p/>

            <div id="Div1" class="new">
                <p>This sample shows:</p>
                <ol>
                    <li>How to use the <code>ScriptManager</code> control to set a history point.</li>
                    <li>The <code>ScriptManager</code> control, the <code>EnableHistory</code> and 
                    <code>EnableSecureHistoryState</code> properties and 
                    the <code>OnNavigate</code> property to handle the <code>navigate</code>event.<br />
                    </li>
                </ol>
            </div>

            <p>
                In this example, three buttons outside the <code>UpdatePanel</code> control can
                trigger an asynchronous postback. You can see the results of the update through
                the date and time that renders in the Web page along with a value indicating the 
                button that triggered the partial refresh.</p>
            <p>
                When you press a button, the server-side <code>Click</code> event handler for the button 
                stores data and uses the data as a history point. If you click the browser's Back button, 
                you will see the state Web page return to a previous button value, representing the previous 
                button you pressed. However, you will see that the time within the Web page continues to be 
                incremented.
            </p>
            <p>To see the effect of this logic, do the following.</p>

            <ol>
                <li>Press <b>1</b>. See the panel refresh.</li>
                <li>Press <b>3</b>. See the panel refresh.</li>
                <li>Press <b>2</b>. See the panel refresh.</li>
                <li>Press the browser's Back button. Note that the panel is refreshed with previous
                    data, but the date and time are updated to current values.</li>
            </ol>
            <asp:UpdatePanel ID="UpdatePanel1" runat="server">
                <Triggers>
                    <asp:AsyncPostBackTrigger ControlID="Button1" EventName="Click" />
                    <asp:AsyncPostBackTrigger ControlID="Button2" EventName="Click" />
                    <asp:AsyncPostBackTrigger ControlID="Button3" EventName="Click" />
                </Triggers>
                <ContentTemplate>
                    <asp:Panel runat="server" CssClass="box" ID="Content" Height="40px">
                        Date and Time:
                        <%= DateTime.Now.ToLongTimeString() %>
                        <br />
                        Page's refresh state:
                        <asp:Label runat="server" ID="LabelHistoryData" />
                    </asp:Panel>
                </ContentTemplate>
            </asp:UpdatePanel>
            <p />
            <asp:Button runat="server" ID="Button1" Text="Key 1" OnClick="ButtonClick" />
            <asp:Button runat="server" ID="Button2" Text="Key 2" OnClick="ButtonClick" />
            <asp:Button runat="server" ID="Button3" Text="Key 3" OnClick="ButtonClick" />
        </div>
    </form>
</body>
</html>

处理服务器的请求

在请求中检测到服务器状态时,会引发 Navigate 事件。这看起来像是到服务器的异步回发。如果必须确定回发是用于导航还是其他目的,可以查看 IsNavigating 属性。如果该属性设置为 true,则说明回发是作为导航调用而产生的。

下面的示例演示 UpdatePanel 控件内部的 Wizard 服务器控件。当用户在向导中导航时,会导致 Wizard 控件执行异步回发。在本示例中,当执行向导中的步骤时,代码会添加历史时间点。

运行此功能的示例。

<%@ Page Language="VB" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">
    Private Shared stepKey As String = "s"

    Protected Sub OnNavigateHistory(ByVal sender As Object, ByVal args As HistoryEventArgs)
        Dim stateString As String = args.State(stepKey)
        Dim [step] As Integer = If(stateString IsNot Nothing, Integer.Parse(stateString), 0)
        MachineConfiguratorWizard.ActiveStepIndex = [step]
    End Sub

    Protected Sub OnActiveStepChanged(ByVal sender As Object, ByVal e As EventArgs)
        If Not ScriptManager1.IsNavigating AndAlso IsPostBack Then
            Dim index As Integer = MachineConfiguratorWizard.ActiveStepIndex
            ScriptManager1.AddHistoryPoint(stepKey, index.ToString(), "Step " + (index + 1).ToString())
        End If
    End Sub
</script>

<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>Microsoft ASP.NET 3.5 Extensions: Managing History</title>
    <link href="../../include/qsstyle.css" type="text/css" rel="Stylesheet" />
</head>
<body>
    <div>
    <form id="form1" runat="server">
        <div>
            <asp:ScriptManager runat="server" ID="ScriptManager1" OnNavigate="OnNavigateHistory" 
                EnableHistory="true" EnableSecureHistoryState="false" />
            <h2>
                Microsoft ASP.NET 3.5 Extensions: Adding Server-side Browser History Points</h2>
            <p/>

            <div id="Div1" class="new">
                <p>This sample shows:</p>
                <ol>
                    <li>How to use the <code>ScriptManager</code> control to set a history point.</li>
                    <li>The <code>ScriptManager</code> control, the <code>EnableHistory</code> and 
                    <code>EnableSecureHistoryState</code> properties and 
                    the <code>OnNavigate</code> property to handle the <code>navigate</code> event.
                    </li>
                    <li>Protecting the history code with <code>IsNavigating</code>
                    </li>
                </ol>
            </div>
        <p>
        In this example, the <code>Wizard</code> server control provides it's own navigation, but 
        as each step is selected a history point is added. In order to do this, a history point is only added if the page is not being refreshed beacuse of a history point.</p>
            <asp:UpdatePanel runat="server" ID="WizardPanel">
                <ContentTemplate>
                    <asp:Wizard ID="MachineConfiguratorWizard" runat="server" ActiveStepIndex="0" BackColor="#dddddd"
                        BorderWidth="10" CellPadding="10" CellSpacing="10" Height="200px" Width="700px"
                        FinishPreviousButtonText="<" StartNextButtonText=">" StepNextButtonText=">" StepPreviousButtonText="<"
                        FinishCompleteButtonText="<|>" OnActiveStepChanged="OnActiveStepChanged">
                        <WizardSteps>
                            <asp:WizardStep ID="Step1" runat="server" Title="Step 1">
                                <h2>
                                    STEP 1</h2>
                                <br />
                            </asp:WizardStep>
                            <asp:WizardStep ID="Step2" runat="server" Title="Step 2">
                                <h2>
                                    STEP 2</h2>
                                <br />
                            </asp:WizardStep>
                            <asp:WizardStep ID="Step3" runat="server" Title="Step 3">
                                <h2>
                                    STEP 3</h2>
                                <br />
                            </asp:WizardStep>
                        </WizardSteps>
                        <StepStyle Font-Names="tahoma" Font-Size="Smaller" VerticalAlign="Top" />
                        <SideBarStyle Font-Size="Small" VerticalAlign="Top" BackColor="#FFFFC0" Font-Names="tahoma" />
                        <FinishPreviousButtonStyle BackColor="White" BorderColor="Black" BorderWidth="3px"
                            Font-Names="Tahoma" Font-Size="Medium" />
                        <NavigationButtonStyle BackColor="White" BorderColor="Black" BorderStyle="Solid"
                            BorderWidth="3px" Font-Names="Tahoma" Font-Size="Medium" />
                        <FinishCompleteButtonStyle Font-Names="Tahoma" Font-Size="Medium" />
                    </asp:Wizard>
                </ContentTemplate>
            </asp:UpdatePanel>
    </div>
    </form>
</body>
</html>
<%@ Page Language="C#" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">
    private static readonly string stepKey = "s";

    protected void OnNavigateHistory(object sender, HistoryEventArgs args)
    {
        string stateString = args.State[stepKey];
        int step = (stateString != null) ? int.Parse(stateString) : 0;
        MachineConfiguratorWizard.ActiveStepIndex = step;
    }

    protected void OnActiveStepChanged(object sender, EventArgs e)
    {
        if (!ScriptManager1.IsNavigating && IsPostBack) {
            int index = MachineConfiguratorWizard.ActiveStepIndex;
            ScriptManager1.AddHistoryPoint(stepKey, index.ToString(), "Step " + (index+1).ToString());
        }
    }
</script>

<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>Microsoft ASP.NET 3.5 Extensions: Managing History</title>
    <link href="../../include/qsstyle.css" type="text/css" rel="Stylesheet" />
</head>
<body>
    <div>
    <form id="form1" runat="server">
        <div>
            <asp:ScriptManager runat="server" ID="ScriptManager1" OnNavigate="OnNavigateHistory" 
                EnableHistory="true" EnableSecureHistoryState="false" />
            <h2>
                Microsoft ASP.NET 3.5 Extensions: Adding Server-side Browser History Points</h2>
            <p/>

            <div id="Div1" class="new">
                <p>This sample shows:</p>
                <ol>
                    <li>How to use the <code>ScriptManager</code> control to set a history point.</li>
                    <li>The <code>ScriptManager</code> control, the <code>EnableHistory</code> and 
                    <code>EnableSecureHistoryState</code> properties and 
                    the <code>OnNavigate</code> property to handle the <code>navigate</code> event.
                    </li>
                    <li>Protecting the history code with <code>IsNavigating</code>
                    </li>
                </ol>
            </div>
        <p>
        In this example, the <code>Wizard</code> server control provides it's own navigation, but 
        as each step is selected a history point is added. In order to do this, a history point is only added if the page is not being refreshed beacuse of a history point.</p>
            <asp:UpdatePanel runat="server" ID="WizardPanel">
                <ContentTemplate>
                    <asp:Wizard ID="MachineConfiguratorWizard" runat="server" ActiveStepIndex="0" BackColor="#dddddd"
                        BorderWidth="10" CellPadding="10" CellSpacing="10" Height="200px" Width="700px"
                        FinishPreviousButtonText="<" StartNextButtonText=">" StepNextButtonText=">" StepPreviousButtonText="<"
                        FinishCompleteButtonText="<|>" OnActiveStepChanged="OnActiveStepChanged">
                        <WizardSteps>
                            <asp:WizardStep ID="Step1" runat="server" Title="Step 1">
                                <h2>
                                    STEP 1</h2>
                                <br />
                            </asp:WizardStep>
                            <asp:WizardStep ID="Step2" runat="server" Title="Step 2">
                                <h2>
                                    STEP 2</h2>
                                <br />
                            </asp:WizardStep>
                            <asp:WizardStep ID="Step3" runat="server" Title="Step 3">
                                <h2>
                                    STEP 3</h2>
                                <br />
                            </asp:WizardStep>
                        </WizardSteps>
                        <StepStyle Font-Names="tahoma" Font-Size="Smaller" VerticalAlign="Top" />
                        <SideBarStyle Font-Size="Small" VerticalAlign="Top" BackColor="#FFFFC0" Font-Names="tahoma" />
                        <FinishPreviousButtonStyle BackColor="White" BorderColor="Black" BorderWidth="3px"
                            Font-Names="Tahoma" Font-Size="Medium" />
                        <NavigationButtonStyle BackColor="White" BorderColor="Black" BorderStyle="Solid"
                            BorderWidth="3px" Font-Names="Tahoma" Font-Size="Medium" />
                        <FinishCompleteButtonStyle Font-Names="Tahoma" Font-Size="Medium" />
                    </asp:Wizard>
                </ContentTemplate>
            </asp:UpdatePanel>
    </div>
    </form>
</body>
</html>

URL 和服务器历史记录状态

创建历史时间点时,需确定要为历史时间点状态存储的信息。至少,必须使用一个键/值对来向应用程序标明状态。您可能还会存储其他的键/值对。但是,因为这些信息存储在 URL 中,而 URL 有大小限制(由浏览器决定),所以应当仅存储重新创建状态所需的信息。

在 URL 中,服务器状态信息可以采用哈希形式,也可以采用非哈希形式,具体取决于您为 ScriptManager 服务器控件的 EnableHistory 属性定义的设置。

历史记录状态在 URL 中以字符 #(片段分隔符)分隔。状态信息跟在“&&”分隔符的后面,如下面的示例所示:

Default.aspx#&&s=Key+2

EnableHistory 设置为 true 时,历史记录状态片段在追加到网页 URL 之前会先加密。这样攻击者很难更改状态数据,从而提高了安全性。但是,即使信息已加密,状态字段中也不会存储敏感数据。

请注意哈希状态信息创建的 URL 较长,并且包括对用户无意义的信息。

向历史时间点中添加标题

浏览器历史记录堆栈中的项通常由该项的页标题标识。要查看相关的示例,请使用浏览器的历史记录列表来查看最近访问过的页面的标题。(通常可以使用 URL 地址框中的下拉列表来查看该列表。)

在应用程序中创建历史时间点项时,默认情况下,使用页标题来标识该项。如果从同一页添加多个历史时间点,则默认情况下,所有的项都将具有相同的标题。

但是,可以为各个历史记录项提供有意义的标题。在服务器代码中,通过调用 AddHistoryPoint 方法创建历史时间点时,可以包括标题信息。

下面的示例通过包括标题项演示前面示例的一种变体形式。

运行此功能的示例。

<%@ Page Language="VB" %>
<%@ Import Namespace="System.Globalization" %>
<%@ Import Namespace="System.Collections.Generic" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">
    Private Shared key As String = "s"

    ' Handle the Navigate event
    Public Sub OnNavigateHistory(ByVal sender As Object, ByVal e As HistoryEventArgs)
        LabelHistoryData.Text = Server.HtmlEncode(e.State(key))
    End Sub

    ' On button click, handle the event and set a history point. 
    Public Sub ButtonClick(ByVal sender As Object, ByVal e As EventArgs)
        LabelHistoryData.Text = CType(sender, Button).Text
        ScriptManager.GetCurrent(Me).AddHistoryPoint(key, LabelHistoryData.Text, "Entry: " + LabelHistoryData.Text)
    End Sub
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
    <title>Microsoft ASP.NET 3.5 Extensions: Managing History</title>
    <link href="../../include/qsstyle.css" type="text/css" rel="Stylesheet" />
</head>
<body>
    <form id="form1" runat="server">
        <div>
            <asp:ScriptManager runat="server" ID="ScriptManager1" OnNavigate="OnNavigateHistory" 
                EnableHistory="true" EnableSecureHistoryState="false" />
            <h2>
                Microsoft ASP.NET 3.5 Extensions: Adding Server-side Browser History Points</h2>
            <p/>

            <div id="Div1" class="new">
                <p>This sample shows:</p>
                <ol>
                    <li>How to use the <code>ScriptManager</code> control to set a history point.</li>
                    <li>The <code>ScriptManager</code> control, the <code>EnableHistory</code> and 
                    <code>EnableSecureHistoryState</code> properties and 
                    the <code>OnNavigate</code> property to handle the <code>navigate</code>event.<br />
                    </li>
                </ol>
            </div>

            <p>
                In this example, three buttons outside the <code>UpdatePanel</code> control can
                trigger an asynchronous postback. You can see the results of the update through
                the date and time that renders in the Web page along with a value indicating the 
                button that triggered the partial refresh.</p>
            <p>
                When you press a button, the server-side <code>Click</code> event handler for the button 
                stores data and uses the data as a history point. If you click the browser's Back button, 
                you will see the state Web page return to a previous button value, representing the previous 
                button you pressed. However, you will see that the time within the Web page continues to be 
                incremented.
            </p>
            <p>To see the effect of this logic, do the following.</p>

            <ol>
                <li>Press <b>1</b>. See the panel refresh.</li>
                <li>Press <b>3</b>. See the panel refresh.</li>
                <li>Press <b>2</b>. See the panel refresh.</li>
                <li>Press the browser's Back button. Note that the panel is refreshed with previous
                    data, but the date and time are updated to current values.</li>
            </ol>
            <asp:UpdatePanel ID="UpdatePanel1" runat="server">
                <Triggers>
                    <asp:AsyncPostBackTrigger ControlID="Button1" EventName="Click" />
                    <asp:AsyncPostBackTrigger ControlID="Button2" EventName="Click" />
                    <asp:AsyncPostBackTrigger ControlID="Button3" EventName="Click" />
                </Triggers>
                <ContentTemplate>
                    <asp:Panel runat="server" CssClass="box" ID="Content" Height="40px">
                        Date and Time:
                        <%= DateTime.Now.ToLongTimeString() %>
                        <br />
                        Page's refresh state:
                        <asp:Label runat="server" ID="LabelHistoryData" />
                    </asp:Panel>
                </ContentTemplate>
            </asp:UpdatePanel>
            <p />
            <asp:Button runat="server" ID="Button1" Text="Key 1" OnClick="ButtonClick" />
            <asp:Button runat="server" ID="Button2" Text="Key 2" OnClick="ButtonClick" />
            <asp:Button runat="server" ID="Button3" Text="Key 3" OnClick="ButtonClick" />
        </div>
    </form>
</body>
</html>
<%@ Page Language="C#" %>
<%@ Import Namespace="System.Globalization" %>
<%@ Import Namespace="System.Collections.Generic" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">
    private static String key = "s";

    // Handle the Navigate event
    public void OnNavigateHistory(object sender, HistoryEventArgs e) {
        LabelHistoryData.Text = Server.HtmlEncode(e.State[key]);
    }

    // On button click, handle the event and set a history point. 
    public void ButtonClick(object sender, EventArgs e) {
        LabelHistoryData.Text = ((Button)sender).Text;
        ScriptManager.GetCurrent(this).AddHistoryPoint(key, LabelHistoryData.Text, "Entry: " + LabelHistoryData.Text);
    }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
    <title>Microsoft ASP.NET 3.5 Extensions: Managing History</title>
    <link href="../../include/qsstyle.css" type="text/css" rel="Stylesheet" />
</head>
<body>
    <form id="form1" runat="server">
        <div>
            <asp:ScriptManager runat="server" ID="ScriptManager1" OnNavigate="OnNavigateHistory" 
                EnableHistory="true" EnableSecureHistoryState="false" />
            <h2>
                Microsoft ASP.NET 3.5 Extensions: Adding Server-side Browser History Points and Title Entries</h2>
            <p/>

            <div id="Div1" class="new">
                <p>This sample shows:</p>
                <ol>
                    <li>How to use the <code>ScriptManager</code> control to set a history point and add titles.</li>
                    <li>The <code>ScriptManager</code> control, the <code>EnableHistory</code> and 
                    <code>EnableSecureHistoryState</code> properties and 
                    the <code>OnNavigate</code> property to handle the <code>navigate</code>event.<br />
                    </li>
                </ol>
            </div>

            <p>
                In this example, three buttons outside the <code>UpdatePanel</code> control can
                trigger an asynchronous postback. You can see the results of the update through
                the date and time that renders in the Web page along with a value indicating the 
                button that triggered the partial refresh.</p>
            <p>
                When you press a button, the server-side <code>Click</code> event handler for the button 
                stores data and uses the data as a history point. If you click the browser's Back button, 
                you will see the state Web page return to a previous button value, representing the previous 
                button you pressed. However, you will see that the time within the Web page continues to be 
                incremented.
            </p>
            <p>To see the effect of this logic, do the following.</p>

            <ol>
                <li>Press <b>1</b>. See the panel refresh.</li>
                <li>Press <b>3</b>. See the panel refresh.</li>
                <li>Press <b>2</b>. See the panel refresh.</li>
                <li>Press the browser's Back button. Note that the panel is refreshed with previous
                    data, but the date and time are updated to current values.</li>
                <li>Press the browser's "Recent Pages" drop down menu and review the history entries and their titles.</li>
            </ol>
            <asp:UpdatePanel ID="UpdatePanel1" runat="server">
                <Triggers>
                    <asp:AsyncPostBackTrigger ControlID="Button1" EventName="Click" />
                    <asp:AsyncPostBackTrigger ControlID="Button2" EventName="Click" />
                    <asp:AsyncPostBackTrigger ControlID="Button3" EventName="Click" />
                </Triggers>
                <ContentTemplate>
                    <asp:Panel runat="server" CssClass="box" ID="Content" Height="40px">
                        Date and Time:
                        <%= DateTime.Now.ToLongTimeString() %>
                        <br />
                        Page's refresh state:
                        <asp:Label runat="server" ID="LabelHistoryData" />
                    </asp:Panel>
                </ContentTemplate>
            </asp:UpdatePanel>
            <p />
            <asp:Button runat="server" ID="Button1" Text="Key 1" OnClick="ButtonClick" />
            <asp:Button runat="server" ID="Button2" Text="Key 2" OnClick="ButtonClick" />
            <asp:Button runat="server" ID="Button3" Text="Key 3" OnClick="ButtonClick" />
        </div>
    </form>
</body>
</html>

请参见

其他资源

管理浏览器历史记录