WebSurfer's Home

トップ > Blog 1   |   ログイン
APMLフィルター

UpdatePanel と ListView

by WebSurfer 2016年11月20日 17:24

先に今回の事例から学んだ教訓を書いておきます。ちょっと今さらながらの感がありますが。

ASP.NET 4 以降では、UpdatePanel を使って非同期ポストバックを行う場合、ポストバックのトリガとするコントロールの ClientIDMode プロパティはデフォルトではなく AutoID にしておくこと。

UpdatePanel に LinkButton を含む ListView を配置した場合、LinkButton をクリックしても非同期ポストバックとならず、同期ポストバックになることからこの問題に気がつきました。(注: GridView の場合は非同期ポストバックがかかります・・・理由後述)

UpdatePanel と ListView

これは LinkButton に限らず、ASP.NET が自動生成するスクリプトの __doPostBack メソッドを利用してポストバックをかけるコントロールすべてに同様です。例えば TextBox の AutoPostBack プロパティを true にしたような場合も非同期ポストバックはかかりません。

そもそもの原因は ASP.NET サイトの記事 ASP.NET 4 Breaking Changes / ClientIDMode Changes にあるように、ASP.NET 4 からは ClientID の命名がデフォルトで Predictable となったからです。(正確に言うと、コントロールの ClientIDMode はデフォルトで Inherit だが、ページの ClientIDMode はデフォルトで Predictable なので、それを継承して結果的に Predictable になるということです)

ScriptManager が生成するスクリプトは前の方法、すなわち AutoID モードでの ClientID を期待しているので、デフォルトの Predictable では非同期ポストバックのトリガとなるコントロールとしては認識されません。

具体的にどういう話かというと、以下の通りです。

上の画像のように ListView 内に LinkButton を配置すると、ASP.NET がそれを html ソースにレンダリングする時、ClientIDMode が Predictable の場合と AutoID の場合とで id は以下のように異なります。上が Predictable、下が AutoID の場合です。

<a id="ListView1_LinkButton1_0" 
 href="javascript:__doPostBack('ListView1$ctrl0$LinkButton1','')">
 LinkButton
</a>

<a id="ListView1_ctrl0_LinkButton1"
 href="javascript:__doPostBack('ListView1$ctrl0$LinkButton1','')">
 LinkButton
</a>

__doPostBack メソッドの第一引数にはコントロールの UniqueID が設定されます。UniqueID の命名規則は、親名前付けコンテナーの ID 値とコントロールの ID 値を '$' で連結するもので、上の例では 'ListView1$ctrl0$LinkButton1' となります。

AutoID の場合、UniqueID の '$' を '_' に置き換えた文字列が id の文字列と同じになるとことに注目してください。Predictable ではそうはなりません。

ScriptManager がページに配置されると、それが生成する JavaScript のコードでポストバックを制御するようになりますが、その時 UniqueID を使ってトリガとなった html 要素を探し、同期 or 非同期どちらのトリガになるかを判定します。

具体的には、ScriptManager が生成する _doPostBack という名前のメソッドの中で、ポストバックのトリガとなったコントロールの UniqueID の '$' を '_' に変換した id で getElementById メソッドを使って要素を探しに行きます。

なので、ClientIDMode がデフォルトでは見つからない、AutoID の場合は見つかるということになります。

上のステップで html 要素が見つかった場合は非同期ポストバックのトリガと判定され、直ちに非同期ポストバックがかかるようになっています。

上のステップで直接当該要素を見つけられなかった場合は、_findNearestElement というメソッドを使って上位の要素を探しに行きます。上の例の html ソースの UniqueID の場合は最終的に ListView1 という名前の id の要素を探しに行きます。

ところが ID="ListView1" という ListView コントロールから ASP.NET が生成する html 要素(table)の id は "ListView1_itemPlaceholderContainer" になり、ListView1 という名前の id の要素は見つからないという結果になります。

直接見つからず、その親も見つからなかった場合は、当該要素は非同期ポストバックのトリガとは見なされず、同期ポストパックがかかるという結果になります。

ただし、ListView に代えて GirdView を使った場合は、その中に配置した LinkButton クリックでも非同期ポストパックがかかります。その理由は、例えばサーバー側での ID を "GridView1" とした場合、html 要素(table)の id は同じく "GridView1" になるので、_findNearestElement メソッドで親が見つかるからです。

しかし、やはり正解は、ListView、GridView に関係なく、UpdatePanel を使って非同期ポストバックを行う場合トリガとするコントロールの ClientIDMode プロパティは AutoID にしておくことだと思います。

Tags: , ,

AJAX

About this blog

2010年5月にこのブログを立ち上げました。その後 ブログ2 を追加し、ここは ASP.NET 関係のトピックス、ブログ2はそれ以外のトピックスに分けました。

Calendar

<<  2017年2月  >>
2930311234
567891011
12131415161718
19202122232425
2627281234
567891011

View posts in large calendar