atsukanrockのブログ

Microsoft系技術を中心にぼちぼち更新します

ユーザーコントロール内のコントロールに対する妥当性検証

はじめに

ASP.NETのユーザーコントロール内に配置したコントロールに対し、妥当性検証を行いたいとする。その際のValidatorのControlToValidateプロパティの指定方法を示す。

指定方法

<ユーザーコントロールのID>:<ユーザーコントロール内に配置したコントロールのID>

「ユーザーコントロールなのだから、Validatorもユーザーコントロール内に配置すべき」なのだろうが、ユーザーコントロールの外側にValidatorを配置したいときもある。そんなときに上記の記述法が使える。
例えば、

<%-- ユーザーコントロールのソースコード(Hoge.ascx)内での記述 --%>
<asp:TextBox ID="txtFuga" runat="server" />

<%-- ユーザーコントロールを配置するaspxファイルでの記述1 --%>
<%@ Register Src="~/Hoge.ascx" TagName="Hoge" TagPrefix="uc" %>

<%-- ユーザーコントロールを配置するaspxファイルでの記述2 --%>
<uc:Hoge ID="hoge" runat="server" />

のようなコードだとして、Validatorのコードは以下のようになる。

<asp:RequiredFieldValidator ID="vdtHoge" runat="server" ControlToValidate="hoge:txtFuga" ... />

「今のは悪い見本」なのだが…

カプセル化が全く成立しておらず、txtFugaテキストボックスのIDを変更しただけでユーザーコントロールを配置している画面の動作に影響が出ることになるが、ユーザーコントロールの外側にValidatorを配置したい場合にはこの方法しかない。
ちなみに、ユーザーコントロールValidationProperty属性を適用すれば、本エントリで紹介している記述法(以降「:記法」と呼ぶ)を使わなくとも、サーバーサイドValidationを動作させることはできる。しかし、クライアントサイドValidationを動作させるには、やはり:記法が必要になる。

汎用的な表現をすると

エントリの取っ掛かりのために、

  1. ユーザーコントロール
  2. ユーザーコントロール内に配置したコントロール
  3. ValidatorのControlToValidate

という非常に限られた範囲で説明したが、実はこの話は

  1. INamingContainerインターフェイスを実装するコントロールMSDNライブラリの表現だと「名前付けコンテナ」)
  2. 名前付けコンテナ内にネストされたコントロール
  3. コントロールIDを指定する全てのプロパティ

という条件下で常に成立する。
結局のところControl.FindControlメソッドのドキュメント化されていない実装を利用しているのだ。これは本当はやってはいけないことで、ドキュメント化されていないということは、ASP.NETのバージョンが変われば使えなくなる記述かもしれないということだ。どうしても必要に迫られた場合(ユーザーコントロールソースコードを変更できる場合は、当てはまることはないはずだ)を除いては、使わない方が良いだろう。

ちなみに

:記法は「:」の部分を「$」にしても使える。「$」はControl.UniqueIDプロパティの名前付けコンテナ間の区切り文字と同じで何となく気持ち悪いので、本エントリでは「:」を使った。