Update Panelについての備忘録(ステートレス/フル通信の違い)

こんにちは。

今回はASP.NETで今は必要不可欠な技術と言える、
ASP.NET AJAXの肝となるコントロールであるUpdate Panelについて、
まとめた記事になります。

#Update Panelの基礎について#

注意していただきたいのは
Update Panelは一般的に言われているAjaxとは似て非なる物であり
あくまで擬似的にAjaxを再現しているに過ぎません。

ではどのあたりが擬似的なのか説明する前に、
基本的なwebのリクエストとレスポンスのやり取りについて説明いたします。

###①ステートレス通信について###
サーバーを定食屋さん、クライアントをそのお客さんだとします。

まず、クライアントがサーバーに注文をします。
お客さんA「*カツ丼定食をお願いします。*」
↑　これがクライアントからのリクエストになります。

ここでサーバーの定食屋さんのご主人が
カツ丼定食を厨房でこしらえお盆に載せて持ってきますね。
ご主人「*はいよ！　カツ丼定食１丁！*」
↑　これがサーバーからのレスポンスになります。

さて、ここでお客さんがカツ丼定食を頼んですぐに
追加でドリンクを頼んだとしましょう。

現実の世界では
お客さんA「*追加でドリンクをお願いします。*」
で注文は解決します。

何故なら**お客さんAが注文した状況をご主人が把握している**為に
ご主人は「*カツ丼定食　+　ドリンクだな。*」
と理解できるからです。

**これがステートフル通信になります。**
クライアントの状態(state)をfullにサーバーが把握しているということです。

しかし、Webの世界ではこうはいきません。
何故なら、Webという定食屋さんのお客さんは
何万人も何十万人にも成り得るからです。
定食屋のご主人がそんなにたくさんのお客さんの情報を
把握しているようではご主人の頭がパンクしてしまいます。

Webの世界で追加の注文をする際にはこういったやり取りになります。

お客さんA「*カツ丼定食をお願いします。ドリンクをお願いします。*」

さらに注文が増えても同じです。
お客さんA「*カツ丼定食をお願いします。ドリンクをお願いします。デザートをお願いします。*」

**ご主人はお客さんAが注文した状況を全く覚えていない**為に
二重の注文をしている訳ではなく毎回改めて注文をしなおす必要があります。

**これがステートレス通信になります。**
クライアントの状態(state)をサーバーが把握していない(less)ということです。

###②Ajaxについて###
先ほどのステートレス通信を行うことで
サーバーのパンクを回避することができましたが、
ここで1つ問題が出てきます。

仮にカツ丼定食のお味噌汁に虫が入っていたとしましょう。

お客さんは再度注文をします。
お客さんA「*カツ丼定食をお願いします。*」
そしてご主人はまた一からカツ丼定食を作り直します。
そしてお盆に載って運ばれてきたカツ丼定食は全てが新品になっています。

これではカツ丼定食を一から作り直すのが非常に手間で時間がかかってしまいますよね。
そこでAjaxが可能とする注文方法が以下になります。

お客さんA「*お味噌汁だけ取り替えてください。*」
そうしてご主人はお味噌汁だけ作り直し運んでくればよい為に
非常に作業が簡略化されます。

**これがAjaxになります。**

画面の部分的なリクエストとレスポンスを可能とし
画面全体の再レンダリングを起こさない為に
画面のちらつきが無くなり、通信を早くすることが可能となります。

###③Update Panelの通信について###
さて先ほど通常のAjaxについて説明しました。
Update Panelの場合ではどうなのでしょうか？

お客さんA「*カツ丼定食を取り替えてください。*」
とお客さんはカツ丼定食丸々を注文します。
そこでご主人は虫が入っていたお味噌汁だけを
厨房で取り替えて運んできます。

Update Panelが擬似的なAjaxであるといったのは以上のような流れで処理が行われるからです。
Update Panelでは画面の一部のみのレンダリングを可能とします。
その為に画面のちらつきはなくなりますが、
裏で行われている処理としては
画面全体のリクエストがクライアントから行われているという事に注意が必要です。

#Update Panelの使い方#
```html:.aspx
<asp:ScriptManager ID="ScriptManager1"　runat="server" />

<asp:UpdatePanel runat="server" ID="UpdatePanel1" UpdateMode="Conditional">
    <ContentTemplate>
        <!--①ここに非同期ポストバックさせたいコントロールを書く。-->         
    </ContentTemplate>
    <Triggers>
        <!--以下で非同期ポストバックを起こさせるイベントを設定-->
        <asp:AsyncPostBackTrigger ControlID="Button1" EventName="Click" />
    </Triggers> 
</asp:UpdatePanel>

<asp:Button runat="server" ID="Button1" />
```
上記のコードのような実装でUpdatePanelを使うことができます。

Form内にScriptManagerコントロールが存在しないと
UpdatePanelは使えないのでまずは最初に書いてあげましょう。

後述しますがChildrenAsTriggerプロパティのデフォルト値がtrueになっているので、
通常は①のContentTemplate内のコントロールで起きたイベントは自動的に
非同期ポストバックのTrigger対象イベントになります。

よって、通常は
UpdatePanel外にあるボタンクリックイベントなどで非同期ポストバックを起こしたいときに
TriggerのAsyncPostBackTriggerを設定します。

UpdatePanelの子コントロールでのみ非同期ポストバックを行う際には、
Trigger句は省略してもいいでしょう。

またTriggerは以下のようにして設定することも出来ます。

```csharp:コードビハインド内
private void Page_Load(object sender, EventArgs e)
{
    this.ScriptManager1.RegisterAsyncPostBackControl(Button1); 
}

private void Button1_Click(object sender, EventArgs e)
{
    this.UpdatePanel1.UpDate();
}
```

コードビハインド内のページロードイベント等で
ScriptManagerからコントロールを
非同期ポストバックの対象に設定してあげて
該当イベント内でUpdatePanelのUpdateメソッドを呼び出してあげます。

#Update Panelの重要なプロパティについて#
##UpdateMode
UpdateModeには2つの値を設定することが出来ます。
**Always**
**Conditional**

**Always**　→　Form内のUpdatePanel内で非同期ポストバックが発生時に
　　　　　　連動して非同期ポストバックが発生。

　　　　　　例えば、UpdatePanel1で非同期ポストバックが発生したとします。
　　　　　　UpdatePanel2がConditional="Always"となっている場合は、
　　　　　　自動的にUpdatePanel2でも非同期ポストバックが発生します。

**Conditional**　→　Form内の他のUpdatePanelとの非同期ポストバックの連動を独立化。

デフォルト値はAlwaysになっています。
「こっちのUpdatePanelは非同期ポストバックをして欲しくない」など
連動させたくないことが多いと思われるので
Conditionalへ設定し直すことをおすすめします。

##ChildrenAsTrigger
bool値を設定します。

名の如くですが、trueにするとUpdatePanelに含まれる子コントロールが
非同期ポストバックのTriggerに自動で設定されます。

デフォルト値はtrueになっています。


---
参考：[ASP.NET Webフォーム Ajax利用
](http://office-yone.com/blog/asp-net-ajax/)