Kobarin's Development Blog

C#やASP.NET、公開APIなどについての記録です。

LayoutTemplate内にコードブロック

LayoutTemplate内にコードブロックは配置できない

ListViewのLayoutTemplate内にコードブロックが配置できない事、および代替策をメモします。

例えば以下のように、何らかの一覧をulでバインドし、上部に件数を示したいケースを想定します(該当件数の箇所だけListView外に置けばいいだろう、という突っ込みはナシです)。

<asp:ListView id="lv" ...>
  <LayoutTemplate>
    該当件数: <%=_listCount %>
    <ul>
    <asp:PlaceHolder ID="itemPlaceholder ... />
    </ul>
  </LayoutTemplate>
  <ItemTemplate>
    <li><%# Eval("Name") %></li>
  </ItemTemplate>
</asp:ListView>

コードビハインドは以下の通り。

protected _listCount = 0;

protected Page_Load(...) {
  MyCompany mycom = new MyCompany();
  List<Employee> employees = mycom.GetEmployee();
  _listCount = employees.Count;
  lv.DataSource = employees;
  lv.DataBind();
}

これを実行すると、以下の様なエラーになります。

コントロールにコード ブロック (<% ... %>) が含まれているため、コントロールのコレクションを変更できません。

どうやらLayoutTemplate内でコードブロックは使えない事がわかります。

<%# ~ ->にすれば…

次に、「=」を「#」に変えてみました(以下、LayoutTemplate部のみ抜粋)。データバインドをしているので、何となくイケそうな気がしますが…

  <LayoutTemplate>
    該当件数: <%# _listCount %>
    <ul>
    <asp:PlaceHolder ID="itemPlaceholder ... />
    </ul>
  </LayoutTemplate>

結果は、エラーこそ表示されないものの、件数の部分が空欄になってしまいます。

該当件数: ←何も表示されない?!
・田中
・鈴木
・山田

以上の現象から、このListViewの挙動に関して、2つの原因が考えられます。

  1. ListViewのデータバインドはあくまでItemTemplateやGroupTemplateに対してのみであり、LayoutTemplate部は対象外
  2. コードビハインドの実行よりも、LayoutTemplate部のデータバインドが先に実行されてしまっている

ListView_LayoutCreatedイベントで解決

どちらが正しいか分かりませんが、今回もStackOverFlowの過去の書き込みで解決しました。

asp.net - Get public string in codebehind into LayoutTemplate of ListView - Stack Overflow

の中でReplyされている、以下の箇所です。

protected void lv_LayoutCreated(Object sender, EventArgs e)
{
  lv.Controls[0].DataBind();
}

どうやらControls[0]がLayoutTemplateを示すらしく、これは手動でバインドしてやらなると良いようです。
そもそもLayoutTemplateがバインドを自ら行わないから強制的にバインドさせてやる必要があるのか、それともバインドがコードビハインドより先に行われてしまう為に後から再度実行させてやる必要があるのか判然としませんが、とりあえず解決策でした。