階層データを含むクラスがあります。ネストされたリピーターを使用して、ASP.net Webアプリでこのデータを表示したいと思います。どうすればいいですか?ネストのレベルを1つだけにしたことがありますが、5つのレベルを言うにはどうすればよいですか?
各アイテムには、ゼロ個または多数のサブアイテムを含めることができます。基本的に、CSSを使用して各サブレベルでインデントしているだけです。ツリービューコントロールを使用したくありません。リピーターに固執したいです。
更新:
私のデータはデータベースから取得されます。いくつかの基本的なプロパティを持つアイテムデータテーブルがあります。
Item
{
ID,
Name,
Description,
...
}
次に、私は多対多のテーブルを持っています:
Parent
{
ParentID,
ChildID
}
各アイテムを繰り返し処理し、その子を表示しています。およびその子供の子供。ネストされたリピーターでこれを達成するのが最善だと思いますが、間違っている可能性があります。
ItemDataBoundをいじるよりもデータソースを扱う方が常にきれいですが、Repeaterをネストする場合はさらにそうです。
<asp:Repeater DataSource="<%#ColOfCol%>" runat="server">
<ItemTemplate>
<tr>
<asp:Repeater DataSource="<%#Container.DataItem%>" runat="server">
<ItemTemplate>
<td><%#SomeExtractingMethodLikeEval()%></td>
</ItemTemplate>
</asp:Repeater>
</tr>
</ItemTemplate>
</asp:Repeater>
内部データソースは、評価されたプロパティ、または必要な列挙を返すメソッドの呼び出しでもあります。オブジェクトで呼び出されることに注意してください。特定のバージョンを記述してからオーバーロードすることを好みます:
protected IEnumerable<string> GetNames(Family fam)
{
foreach(Person p in fam.Members)
yield return p.FirstName + " " + p.Surname;
}
protected IEnumerable<string> GetNames(object famObj)
{
return GetNames((Family)famObj);
}
注意すべきことの1つは、親リピーターで現在のオブジェクトを取得する場合は、次の方法で取得する必要があることです。
((RepeaterItem)Container.Parent.Parent).DataItem
データバインディングイベントを気にせずにネストされたリピーターを実行する最も簡単な方法は、<%# %>
構文を使用してDataSourceを設定することです。
例えば:
<asp:Repeater runat="server" id="Departments">
<ItemTemplate>
Name: <%# Eval("DeptName") %>
Employees:
<asp:Repeater runat="server" DataSource='<%# Eval("Employees") %>'>
<ItemTemplate><%# Eval("Name") %></ItemTemplate>
<SeparatorTemplate>,</SeparatorTemplate>
</asp:Repeater>
</ItemTemplate>
</asp:Repeater>
これは、DepartmentsクラスにEmployeesプロパティがあることを前提としています-例:
public class Department {
public string DeptName {get; set;}
public IEnumerable<Employee> Employees {get; set;}
}
public class Employee {
public string Name {get; set;}
}
外部リピーターオブジェクトに内部リピーターオブジェクトに対応するプロパティがない場合、計算を行うコードビハインドにメソッドを追加することで、このトリックを使用できます。したがって、内部リピーターは次のようになります。
<asp:Repeater runat="server" DataSource='<%# GetEmployees(Container.DataItem) %>'>
getEmployeesは次のようになります。
protected IEnumerable<Employee> GetEmployees(object item) {
var dept = (Department) item;
// then do whatever is necessary to get the employees from dept
return employees;
}
問題なくリピーターをネストできます。しかし、2レベルを超えると厄介になります。方法は次のとおりです。
Htmlは次のようになります。
<asp:Repeater ID="r1" runat="server" OnItemDataBound="r1_ItemDataBound">
<ItemTemplate>
<!-- top level repeater element template here -->
<asp:Repeater ID="r2" runat="server" onitemdatabound="r2_ItemDataBound">
<ItemTemplate>
<!-- child repeater element template here -->
</ItemTemplate>
</asp:Repeater>
</ItemTemplate>
</asp:Repeater>
分離コードは次のようになります。
protected void r1_ItemDataBound(object sender, RepeaterItemEventArgs e) {
Repeater r2 = (Repeater)e.Item.FindControl("r2");
r2.DataSource = yourDataSourceHere; // you'll have to query for appropriate data
r2.DataBind();
}
protected void r2_ItemDataBound(object sender, RepeaterItemEventArgs e) {
// do the same thing here for the 3rd nested repeater if you have a third, and so on
}
<asp:Repeater ID="R1" runat="server">
<ItemTemplate>
<asp:Repeater ID="R2" runat="server">
</asp:Repeater>
</ItemTemplate>
</asp:Repeater>
R1.ItemDataBound += (s, e) =>
{
var r2 = e.Item.FindControl("R2") as Repeater;
r2.DataSource = something;
r2.DataBind();
};
FindControl
は再帰的ではなく、子のみを取得することに注意してください。