ajaxToolkit:PopupControlExtender のポップアップで TextBox を表示して ENTER を押すと困ったかんじ

たとえば、

<asp:Label ID="Label1" />
<ajaxToolkit:PopupControlExtender TargetControlID="Label1" PopupControlID="Panel1" /> <asp:Button />
<asp:Panel ID="Panel1">
<asp:UpdatePanel><ContentTemplate>
  <asp:TextBox OnChanged="TextBox1_Changed" AutoPostback="True" />
</ContentTemplate></asp:UpdatePanel>
</asp:Panel>

こんなかんじだろうか。ここで TextBox1_Changed から PopupControlExtender.Commit() を実施し、ENETR キーを押さないでポップアップを閉じるとうまいこと動くのだが、ENTER キーを押すとブラウザがボタンを押して通常の Postback を発生させる。
そうすると、TextBox1_Changed が UpdatePanel の内部と外部で呼び出され、外部からの通常の Postback で PopupControlExtender.Commit() を実行しようとして失敗する。
対応案としては、

  • TextBox1_Changed 内で通常の Postback の場合には何もしないようにする
  • ENTER キーで通常の Postback を発生しないようにする
  • ENTER キーで UpdatePanel の更新が発生するようにする

あたりなんだが、まず最初の方法は、通常の Postback と UpdatePanel の更新のための Postback の判別方法がわからなかった。*1
Client Callback も Microsoft Ajax も、非同期リクエストをうけると Page のインスタンスを生成し、*2そのインスタンスで通常通りの処理を行うんだが、Client Callback では Page.IsCallback が true になるのに対して、Microsoft Ajax では類似の判断要素を発見することができなかった。Microsoft Ajax の場合は、複数の UpdatePanel を同時に更新するため、データキューが ScriptManager で管理されるので ScriptManager あたりに判別プロパティがありそうなもんなんだが。
次に2番目の方法だが、今回の場合、MSDN の kb にあるような keydown イベントを使用することは出来ない。これは、keydown イベントに何を設定しようが、 PopupControlExtender がそれを上書きしてしまうためで、同様の理由で asp:Panel の DefaultButton プロパティも機能しない。
3番目の方法は、ブラウザが押したがるボタンを UpdatePanel の中に配置したり、既存のボタンを UpdatePanel の中に移動したり、Triggers に登録する。

*1:IsInAsyncPostBack がそれっぽいんだけど

*2:このことはパフォーマンスに深刻な影響を与えかねないので、Client Callback や Microsoft Ajax を利用する場合に留意しておく必要がある。