雑記 - otherwise

最近はDQ10しかやっていないダメ技術者がちまちまと綴る雑記帳

AJAX Control Toolkit Accordion に階層データをバインドする

# タイトルにいまひとつ自信がないけど。。。
ちょっとしたデモ(お仕事)向けに AJAX Control Toolkit の Accordion コンポーネントを使おうと思ったら、やたらと苦労したので備忘録として書いておきます。
……ってか、これって一般的じゃないのかなぁ。検索しても全然情報が見つからなかったんだけど。。。

バインドするデータクラス

class Foo {
  public string Title { get; set; }
  public List<Bar> Items { get; set; }
}

class Bar {
  public string Content { get; set; }
}

UI (アコーディオン部分のみ抜粋)

<AspControlToolkit:Accordion
    ID="Accordion1"
    runat="server"
    RequireOpenedPane="false"
    FadeTransitions="true"
    onitemdatabound="Accordion1_ItemDataBound">
  <HeaderTemplate><%# Eval("Title") %></HeaderTemplate>
  <ContentTemplate>
    <asp:Repeater ID="Repeater1" runat="server">
      <HeaderTemplate><ul></HeaderTemplate>
      <ItemTemplate><li><%# ((Bar)Container.DataItem).Content %></li></ItemTemplate>
      <FooterTemplate></ul></FooterTemplate>
    </asp:Repeater>
  </ContentTemplate>
</AspControlToolkit:Accordion>

コードビハインド

public partial class MenuSample : System.Web.UI.Page {

  protected void Page_Load(object sender, EventArgs e) {
    List<Foo> items = MakeSample();
    this.Accordion1.DataSource = items;
    this.Accordion1.DataBind();
  }

  protected void Accordion1_ItemDataBound(object sender, AjaxControlToolkit.AccordionItemEventArgs e) {
    if (e.ItemType != AjaxControlToolkit.AccordionItemType.Content) {
      return;
    }
    var panel = e.AccordionItem;
    var repeater = panel.Controls[1] as Repeater;
    if (repeater == null) {
      return;
    }
    var node = e.AccordionItem.DataItem as Foo;
    if (node == null) {
      return;
    }
    if (node.Items == null || node.Items.Count == 0) {
      return;
    }
    repeater.DataSource = node.Items;
    repeater.DataBind();
  }

  List<Foo> MakeSample() {
    return new List<Foo>() {
      new Foo() {
        Title = "サンプル1",
        Items = new List<Bar>() {
          new Bar() { Content = "サンプルアイテム1" },
          new Bar() { Content = "サンプルアイテム2" },
          new Bar() { Content = "サンプルアイテム3" },
          new Bar() { Content = "サンプルアイテム4" },
          new Bar() { Content = "サンプルアイテム5" }
        }
      },
      new Foo() {
        Title = "サンプル2",
        Items = new List<Bar>() {
          new Bar() { Content = "サンプルアイテム6" },
          new Bar() { Content = "サンプルアイテム7" }
        }
      },
      new Foo() {
        Title = "サンプル3",
        Items = new List<Bar>() {
          new Bar() { Content = "サンプルアイテム8" },
          new Bar() { Content = "サンプルアイテム9" },
          new Bar() { Content = "サンプルアイテム10" },
          new Bar() { Content = "サンプルアイテム11" }
        }
      }
    };
  }
}

OnItemDataBound イベントを拾って子リストのバインドを実装してあげなきゃいけないんですね。
この位はコンポーネント側でよろしくやって欲しいなぁ、と。。。