I'm having a bit of a challenge to create the following:
I need to generate a number of fixed sized tables of 2 columns and 4 rows in ASP.NET based on an xml content. So my html container is a multiple of table with a fixed sized 2 columns by 4 rows. In each table, each column will hold an [item] from the xml, where the top cell in the column is the [category] tag, and the 3 cells underneath holds the [make#] tags; so one for each [make#] for a total of 4 rows in the column. So a Table can hold 2 [item] ; one for each column.
Assuming my source is from an XML file:
<items>
<item>
<category>Cat 1</category>
<make1>101</make1>
<make2>102</make2>
<make3>103</make3>
</item>
<item>
<category>Cat 2</category>
<make1>201</make1>
<make2>202</make2>
<make3>203</make3>
</item>
<item>
<category>Cat 3</category>
<make1>301</make1>
<make2>302</make2>
<make3>303</make3>
</item>
<item>
<category>Cat 4</category>
<make1>401</make1>
<make2></make2>
<make3></make3>
</item>
<item>
<category>Cat 5</category>
<make1>501</make1>
<make2>502</make2>
<make3</make3>
</item>
</items>
and my desired output for the 5 categories where each category can have up to 3 items underneath in html is:
<table>
<tr> <td>Cat 1</td> <td>Cat 2</td> </tr>
<tr> <td>101</td> <td>201</td> </tr>
<tr> <td>102</td> <td>202</td> </tr>
<tr> <td>103</td> <td>203</td> </tr>
</table>
<table>
<tr> <td>Cat 3</td> <td>Cat 4</td> </tr>
<tr> <td>301</td> <td>401</td> </tr>
<tr> <td>302</td> <td> </td> </tr>
<tr> <td>303</td> <td> </td> </tr>
</table>
<table>
<tr> <td>Cat 5</td> <td> </td> </tr>
<tr> <td>501</td> <td> </td> </tr>
<tr> <td>502</td> <td> </td> </tr>
<tr> <td> </td> <td> </td> </tr>
</table>
How would I achieve this?
Note I need tables because I'm using a carousel with a hard coded carousel with that structure...
After some discussion I think we came to the conclusion that the repeater method is not the best route to take. The basic problem here is how to input two entities side-by-side. There is an asp.net control built for this: the DataList.
With the DataList, you can set the maximum number of items to repeat as well as the direction to repeat the items (Horizontal / Vertical).
So, with that, you will want to add the following DataList code to your aspx page:
<asp:DataList ID="DataList1" runat="server" DataSourceID="XmlDataSource1" RepeatColumns="2" RepeatDirection="Horizontal">
<HeaderTemplate>Items</HeaderTemplate>
<ItemTemplate>
<table border=1>
<tr>
<td>
<%# XPath("category")%>
</td>
</tr>
<tr>
<td>
<%# XPath("make1")%>
</td>
</tr>
<tr>
<td>
<%# XPath("make2")%>
</td>
</tr>
<tr>
<td>
<%# XPath("make3")%>
</td>
</tr>
</table>
</ItemTemplate>
</asp:DataList>
The key here is that each item's data is bound in the <ItemTemplate>
. Then the DataList itself takes care of arranging each item according to the flags RepeatColumns="2"
and RepeatDirection="Horizontal"
.
Some quick <asp:XmlDataSource>
magic:
<asp:XmlDataSource ID="XmlDataSource1" runat="server"
XPath="//items/item">
</asp:XmlDataSource>
Where XPath="//items/item"
points the XmlDataSource to the location of each entity in the xml. This is bound to the DataList with the following tag on the DataList itself: DataSourceID="XmlDataSource1"
On the code-behind file I cheated and just fed the XML as a string:
this.XmlDataSource1.Data = @"<items> <item> <category>Cat 1</category> <make1>101</make1> <make2>102</make2> <make3>103</make3> </item> <item> <category>Cat 2</category> <make1>201</make1> <make2>202</make2> <make3>203</make3> </item> <item> <category>Cat 3</category> <make1>301</make1> <make2>302</make2> <make3>303</make3> </item> <item> <category>Cat 4</category> <make1>401</make1> <make2></make2> <make3></make3> </item> <item> <category>Cat 5</category> <make1>501</make1> <make2>502</make2> <make3></make3> </item> </items>";
And she works!
BTW, I'll never forgive you for the missing ">" in the XML of your original post. Drove me nuts finding it. :)
Now, granted that ideally the best method to do all this is deserializing the xml into .NET classes and binding everything the proper way (ie: code-behind binding of data, etc), but the general idea is there.
Regarding OP comment about nested table issue:
The GridList has a property called RepeatLayout. Setting this property to RepeatLayout.Flow will use other elements rather than tables. From MSDN:
Items are displayed without a table structure. Rendered markup consists of a span element and items are separated by br elements. Layouts for each enum here
Also, this article discusses the differences between the DataGrid, DataList and Repeater MSDN
OLD ANSWER:
I'm thinking along the lines of a Usercontrol that accepts two item entities as parameters.
So if you have a class called Item:
public class Item
{
public string Category{get;set;}
public List<string> Makes { get; set; }
}
And your UserControl looks like this: (ASPX)
<table>
<tr>
<td><asp:Label ID="lblCategory1" runat="server" /></td>
<td><asp:Label ID="lblCategory2" runat="server" /></td>
</tr>
<asp:Repeater ID="rptMakes" runat="server">
<HeaderTemplate><tr></tr></HeaderTemplate>
<ItemTemplate>
<td>
<asp:Label ID="lblMake1" runat="server" />
</td>
<td>
<asp:Label ID="lblMake2" runat="server" />
</td>
</ItemTemplate>
<SeparatorTemplate></tr><tr></SeparatorTemplate>
<FooterTemplate>
</tr>
</FooterTemplate>
</asp:Repeater>
</table>
and like this on the .cs page:
private Item Item2;
protected override void OnInit(EventArgs e)
{
this.rptMakes.ItemDataBound += new RepeaterItemEventHandler(rptMakes_ItemDataBound);
base.OnInit(e);
}
void rptMakes_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
((Label)e.Item.FindControl("lblMake1")).Text = e.Item.DataItem.ToString();
if (this.Item2 != null)
{
((Label)e.Item.FindControl("lblMake2")).Text = this.Item2.Makes[e.Item.ItemIndex];
}
else
{
((Label)e.Item.FindControl("lblMake2")).Text = " ";
}
}
}
protected void Page_Load(object sender, EventArgs e)
{
}
public void Populate(Item item1, Item item2)
{
this.lblCategory1.Text = item1.Category;
if (item2 != null)
{
this.lblCategory2.Text = item2.Category;
}
else
{
this.lblCategory2.Text = " ";
}
this.Item2 = item2;
this.rptMakes.DataSource = item1.Makes;
this.rptMakes.DataBind();
}
From there it is just a matter of iterating over the original list of Item entities on your aspx page and passing out every two entities to a UC.