基本的に、カスタムデータコンテナクラスを持つカスタムテンプレートコントロールがあります。開発者が私のコントロールのインスタンスをページに追加すると、次のように、LayoutTemplateでコントロールを好きなように定義できます。
<ml:MyControl id="MyControl1" runat="server">
<LayoutTemplate>
<span><%#Container.ErrorMessage%></span>
</LayoutTemplate>
</ml:MyControl>
この例は、次のようにページにレンダリングされます。
<span id="MyControl1"><span>
<span>ml_errormessage</span>
</span></span>
コントロールで「ml_errormessage」(Container.ErrorMessageからのデータバインドされたコンテンツ-プロパティ内のハードコードされたトークン)をその要素を含むクラスに自動的に移動して、jQueryがセレクターを使用して要素を見つけやすくするようにします。エラーメッセージのクライアント側を動的に挿入します。さらに重要なのは、クラス名がコンテンツに置き換えられず、jQueryがページのライフサイクル中に必要な回数だけそれを見つけられるように、邪魔にならないように移動したいということです。つまり、開発者が入力テンプレートを変更したり、テンプレートでカスタムコントロールを使用したりせずに、出力を次のように表示したいと思います。
<span id="MyControl1"><span>
<span class="ml_errormessage"></span>
</span></span>
可能であれば、出力の文字列解析に頼るのではなく、controlsコレクションを使用して値を移動したいと思います。ただし、OnPreRenderのオーバーライドでコレクションに問い合わせると、テンプレートのコントロールはデバッガーでは次のようになります。
{System.Web.UI.DataBoundLiteralControl}
System.Web.UI.DataBoundLiteralControl: {System.Web.UI.DataBoundLiteralControl}
AppRelativeTemplateSourceDirectory: "~/"
BindingContainer: {MyControls.MyControlData}
ClientID: "MyControl1_ctl01_ctl00"
Controls: {System.Web.UI.EmptyControlCollection}
EnableTheming: True
EnableViewState: True
ID: "ctl00"
NamingContainer: {MyControls.MyControlData}
Page: {ASP.default_aspx}
Parent: {MyControls.MyControlData}
Site: Nothing
SkinID: ""
TemplateControl: {ASP.default_aspx}
TemplateSourceDirectory: "/MyControls"
UniqueID: "MyControl1$ctl01$ctl00"
Visible: True
ご覧のとおり、「ml_errormessage」の値はどこにも見つかりません。Reflectorを使用してControlクラスのDataBindイベントを分析すると、バインディング動作が各コントロールに委任されていることがわかります。つまり、各コントロールは独自のデータバインディングを処理します。ただし、テンプレートにどのコントロールタイプが含まれるかを事前に知る方法がないため、この変更をどのように行うことができますか?
注:許容できる代替手段は、「ml_errormessage」がある正確な場所に新しいHtmlGenericControl(スパン)を追加し、それをクラスとしてこの新しいコントロールに追加することです。
ちなみに、デバッグ中に読みやすいようにコントロールの出力をインデントする簡単な方法はありますか?