.NET TIPS

[ASP.NET AJAX]AJAX対応ページで[戻る]ボタンを有効にするには?(サーバサイド編)[3.5、C#、VB]

山田 祥寛
2009/06/18

 Ajax機能を利用したページを構築しているときに、決定的に困ることが1つある。それは、Ajax機能によって変更されたページの状態を維持できない点だ。

 まずは、その具体的な例を見てみよう。以下の例は、おなじみUpdatePanelコントロールを使ったごく基本的な「Hello, Worldアプリケーション」である。テキストボックスに適当な名前を入力して[登録]ボタンをクリックすると、ページの下部に「こんにちは、●○さん!」というメッセージが表示される。普通のページと異なる点は、この際に更新されるのが、ラベルの部分だけであって、ページ全体がリフレッシュされるわけでは「ない」という点だ。



[名前]を入力して[登録]ボタンをクリック

Ajax式のおなじみのHello, Worldアプリケーション
ポストバックの前後で現在時刻の表示が変化していないことから、ページの一部だけがリフレッシュされていることが確認できる。

 このようなサンプルは、以下のような手順で作成できる。なお、ページ上部の時刻表示は、UpdatePanelコントロール以外の部分がリフレッシュされて「いない」ことを確認するためのものである。

History.aspxのフォーム・レイアウト
以下のコントロールを配置。TextBox、Button、LabelコントロールはUpdatePanelコントロールの配下に配置する。
  ScriptManagerコントロール(IDは「manager」)。
  Labelコントロール(IDは「lblTime」)。
  UpdatePanelコントロール(IDは「upanel」)。
  TextBoxコントロール(IDは「txtName」)。
  Buttonコントロール(IDは「btnSubmit」)。
  Labelコントロール(IDは「lblResult」)。

コントロール プロパティ 設定値
ScriptManager(manager)
Label(lblTime) Text △(ブランク)
UpdatePanel(upanel)
TextBox(txtName)
Button(btnSubmit) Text 登録
Label(lblResult) Text △(ブランク)
History.aspxのプロパティ設定

 あとは、ページ・ロード時に時刻を、ボタン・クリック時にメッセージを、それぞれ表示するためのイベント・ハンドラを追加するだけだ。

protected void btnSubmit_Click(Object sender, EventArgs e) {
  // ボタンクリック時に「こんにちは、●○さん!」を表示
  String msg =
    String.Format("こんにちは、{0}さん!", txtName.Text);
  lblResult.Text = msg;
}

protected void Page_Load(Object sender, EventArgs e) {
  // 非同期通信以外の場合に現在時刻を表示
  if (!manager.IsInAsyncPostBack) {
      lblTime.Text = DateTime.Now.ToString();
  }
}
Protected Sub btnSubmit_Click(ByVal sender As Object, ByVal e As System.EventArgs)
  ' ボタンクリック時に「こんにちは、●○さん!」を表示
  lblResult.Text = _
    String.Format("こんにちは、{0}さん!", txtName.Text)
End Sub

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs)
  ' 非同期通信以外の場合に現在時刻を表示
  If Not manager.IsInAsyncPostBack Then
    lblTime.Text = DateTime.Now.ToString()
  End If
End Sub
ページ・ロード時、[登録]ボタンのクリック時に実行されるイベント・ハンドラ(History.aspx)(上:C#、下:VB)

 この状態で、ページを実行してみよう。冒頭の画面のように、「山田」「掛谷」のような名前を入力すると、それぞれ「こんにちは、山田さん!」「こんにちは、掛谷さん!」のようなメッセージが表示されることが確認できる。

 しかし、ここでブラウザの[戻る][進む]ボタンを確認してみよう。普通のアプリケーションであれば、ボタンをクリックしたところで前のページに戻るために[戻る]ボタンがアクティブになっているはずだ。しかし、実際には[戻る]ボタンは有効になっていない。Ajax機能で実行された操作については、ブラウザの履歴には残らないからだ。つまり、いくつかの操作を行った後、ブラウザを1つ前の元の状態に戻したいと思った場合にも、Ajaxを使ったページではそれができないのだ。

ボタンをクリックした後も、ブラウザの[戻る]ボタンは有効にならない

●ScriptManagerコントロールの履歴機能

 しかし、ASP.NET 3.5のScriptManagerコントロールは、この点、賢く改良されている。Ajax操作の特定のポイントをブラウザ履歴として記録するための仕組みを、標準で提供しているのだ。この履歴機能を利用することで、Ajaxアプリケーションでも最低限のコーディングでブラウザ履歴を有効にすることができる。

 履歴機能を有効にするための具体的な方法は、次のとおり。

  1. 履歴機能を有効にする
  2. 履歴に残すポイント(履歴ポイント)を登録する
  3. 履歴情報に基づいて、ページを復元する

 それでは、ここからは具体的な手順を見ていく。

1. 履歴機能を有効にする

 ScriptManagerコントロールの履歴機能を有効にするには、プロパティ・ウィンドウからScriptManager.EnableHistoryプロパティをTrueに設定するだけでよい。EnableHistoryプロパティのデフォルト値はFalseで、デフォルトの状態では履歴機能は有効化されていないので注意されたい。

2. 履歴に残すポイント(履歴ポイント)を登録する

  次に、[登録]ボタンをクリックしたタイミングで、ページの復元に必要な情報を履歴ポイントとして残しておく必要がある。これには、先ほど作成したClickイベント・ハンドラに、以下のようなコードを追加すればよい(追加部分は太字)。

protected void btnSubmit_Click(Object sender, EventArgs e) {
  String msg =
    String.Format("こんにちは、{0}さん!", txtName.Text);
  lblResult.Text = msg;

  //履歴ポイントの保存
  manager.AddHistoryPoint("name", txtName.Text);
  manager.AddHistoryPoint("msg", msg, msg);
}
Protected Sub btnSubmit_Click(ByVal sender As Object, ByVal e As System.EventArgs)
  Dim msg As String = _
    String.Format("こんにちは、{0}さん!", txtName.Text)
  lblResult.Text = msg

  ' 履歴ポイントの保存
  manager.AddHistoryPoint("name", txtName.Text)
  manager.AddHistoryPoint("msg", msg, msg)
End Sub
[登録]ボタンをクリックしたときに実行されるイベント・ハンドラ(History.aspx)(上:C#、下:VB)

 AddHistoryPointメソッドの引数には、登録すべき情報のキー名、値、ページ・タイトルを指定する(最後のページ・タイトルは省略可)。ここでは、name、msgというキー名で、それぞれ「山田」「こんにちは、山田さん!」のような値を追加し、ページ・タイトルとして「こんにちは、山田さん!」を登録しているわけだ。

 まだサンプルは未完成であるが、ここでいったんサンプルを動作させてみよう。先ほどと同じく名前を入力して、[登録]ボタンをクリックしてみよう。

 すると、どうだろう。今度はブラウザの[戻る]ボタンが有効になっていること、そして、アドレスの末尾に「#&&/wEXAgUDbXNnBSHjgZ……」のような情報が追加されていることが確認できるはずだ。

履歴ポイントを追加した場合の挙動
[戻る]ボタンが有効となり、かつ、アドレス欄の末尾に文字列が追加されている。

 このように、履歴ポイントを追加したことでブラウザ履歴が追加されるわけだ。ちなみに、アドレス末尾の暗号のような文字列は、先ほどAddHistoryPointメソッドで追加されたキー名と値を、ViewStateと同じ方法でハッシュ化したものである。このように、ScriptManagerコントロールでは、ページの状態を後から復元できるように、アドレスの一部として保持している*1

*1 このような事情から、履歴ポイントとして機密情報を登録するのは避けるべきである。

 ちなみに、キー名/値をハッシュ化せずに、より見やすい形で保存したいというケースもあるかもしれない。その場合には、EnableSecureHistoryStateプロパティをFalseに設定すればよい(デフォルトはTrue)。その場合、履歴ポイントの情報はハッシュ処理されずに、以下のように、そのままの形でアドレスに追加されることになる(マルチバイト文字が含まれている場合、エンコード処理は行われる)。

http://localhost:4468/TipsGrid/Toolkit/ScriptManager/history.aspx#&&name=Yamada&msg=〜

3. 履歴情報に基づいて、ページを復元する

 もっとも、2までの手順では、まだ履歴ポイントを追加しただけであるので、[戻る]ボタンを押しても、ページは前の状態には戻らない。ここでもう1つ、ScriptManagerコントロールのNavigateイベントに対応するイベント・ハンドラを追加しておく必要があるのだ。Navigateイベントとは、ブラウザ上で[戻る][進む]などのボタンが押されたときに発生するイベントである。

protected void manager_Navigate(Object sender, HistoryEventArgs e) {

  // キーnameの値が空でない場合に、
  // テキストボックス/ラベルの値を設定
  if (e.State["name"] != "") {
    txtName.Text = e.State["name"];
    lblResult.Text = e.State["msg"];
  } else {
    // キーnameの値が空である場合、テキストボックス/ラベルも空に
    txtName.Text = "";
    lblResult.Text = "";
  }
}
Protected Sub manager_Navigate(ByVal sender As Object, ByVal e As System.Web.UI.HistoryEventArgs)

  ' キーnameの値が空でない場合に、
  ' テキストボックス/ラベルの値を設定
  If e.State("name") <> "" Then
    txtName.Text = e.State("name")
    lblResult.Text = e.State("msg")
  Else
    ' キーnameの値が空である場合、テキストボックス/ラベルも空に
    txtName.Text = ""
    lblResult.Text = ""
  End If
End Sub
[戻る][進む]ボタンをクリックしたときに実行されるイベント・ハンドラ(History.aspx)(上:C#、下:VB)

 履歴ポイントに登録した情報は、Navigateイベント・ハンドラの第2引数として渡されるHistoryEventArgsオブジェクト(System.Web.UI名前空間)から、そのStateプロパティを参照することで取得できる。

 ここでは、履歴ポイントのnameキーが空でない場合に、あらかじめ退避しておいたname/msgキーの値をラベル、テキストボックスにセットし直しているわけだ。これによって、[戻る][進む]ボタンをクリックしたタイミングで、元の状態を復元できる。

 この例を見ても分かるように、ScriptManagerコントロールの履歴機能は、無条件に[戻る][進む]機能を有効にするというものではなく、情報の登録と復元そのものはアプリケーション開発者が自分でコーディングしなければならない、という点に注意してほしい。

 以上を理解できたら、もう一度、サンプルを実行してみよう。名前を入力し、[登録]ボタンをクリックすると、ブラウザ履歴が追加されること、[戻る]ボタンをクリックすると、ページが元の状態に戻ることを確認してほしい。



[戻る]ボタンをクリック

サンプルの最終的な結果
[戻る][進む]ボタンによって、ページの状態が操作前(後)の状態に変化する。

 なお、ブラウザのアドレスをコピーして、別に立ち上げたブラウザに貼り付けてみよう。これによっても、そのときのページの状態が復元されることが確認できるはずだ。End of Article

利用可能バージョン:.NET Framework 3.5 
カテゴリ:
Webフォーム 処理対象:ASP.NET AJAX
使用ライブラリ:ScriptManagerコントロール
使用ライブラリ:UpdatePanelコントロール

この記事と関連性の高い別の.NET TIPS
[ASP.NET AJAX]AJAX対応ページで[戻る]ボタンを有効にするには?(クライアントサイド編)
クラス・ライブラリ内部で呼び出されているメソッドを調べるには?
[ASP.NET]ビューステートに保存されるものは?
[ASP.NET]ポストとポストバックの違いは?
[ASP.NET]DataGridコントロールで編集を可能にするには?
このリストは、(株)デジタルアドバンテージが開発した
自動関連記事探索システム Jigsaw(ジグソー) により自動抽出したものです。
generated by

「.NET TIPS」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間