В aspx:
<table>
<tr>
<asp:Repeater ID="rptHeader" runat="server">
<ItemTemplate>
<th><%#Eval("Category")%></th>
</ItemTemplate>
</asp:Repeater>
</tr>
<tr>
<asp:Repeater ID="rptContents" runat="server">
<ItemTemplate>
<td valign="top">
<%#Eval("Content")%>
</td>
</ItemTemplate>
</asp:Repeater>
</tr>
</table>
В коде:
protected void Page_Load(object sender, EventArgs e)
{
rptHeader.DataSource = DataSource;
rptHeader.DataBind();
rptContentBlocks.DataSource = DataSource;
rptContentBlocks.DataBind();
}
Проблема в том, что вместо использования двух повторителей мы можем использовать только один? Нам действительно нужен заголовок, который нужно отделить от содержимого, используя другую строку таблицы...
Изменить: изменен элемент rtHeader ItemTemplate html от <td>
до <th>
, чтобы быть немного понятнее.: -)
IMO это невозможно без взлома репитера. Во всяком случае, существует довольно нерегулярный подход, который, возможно, работает. Также вы можете использовать два оператора foreach вместо повторителей.
код
protected string[] headers = { "A", "B", "C", "D" };
protected string[] contents = { "Alpha", "Beta", "Counter", "Door" };
//string[] headers = { "A", "B", "C", "D" };
//string[] contents = { "Alpha", "Beta", "Counter", "Door" };
//DataList1.RepeatColumns = headers.Length;
//DataList1.DataSource = headers.Concat(contents);
//DataList1.DataBind();
Разметка HTML
<table>
<tr>
<%foreach (string item in headers)
{ %>
<th><%= item %></th>
<% } %>
</tr>
<tr>
<%foreach (string item in contents)
{ %>
<td><%= item %></td>
<% } %>
</tr>
</table>
<!--
<asp:DataList ID="DataList1" runat="server" RepeatDirection="Horizontal">
<ItemTemplate>
<%# Container.DataItem %>
</ItemTemplate>
</asp:DataList>
-->
<th>
. Спасибо
HTML-таблица всегда объявляется как ячейки, вложенные в строки, т.е.
<table>
<tr>
<td>
...
</td>
</tr>
</table>
а не
<table>
<td>
<tr>
...
</tr>
</td>
</table>
Это означает, что вы не сможете написать ни одного Category
, за которым следует один Content
. Вам придется повторить значения Category
, а затем значения Content
, которые вы уже делаете.
Я не вижу ничего плохого в используемом вами подходе. Использование двух повторителей, а не одного, должно быть незначительным издержками.
Альтернативой будет размещение таблицы в каждом столбце. Это позволит вам использовать только один ретранслятор, но полученный HTML будет довольно надуманным и раздутым. Я бы не рекомендовал этот подход, но каким-то образом я не могу остановить пример.
<table>
<tr>
<asp:Repeater ID="rptHeader" runat="server">
<ItemTemplate>
<td>
<table>
<tr>
<td valign="top">
<strong><%#Eval("Category")%></strong>
</td>
</tr>
<tr>
<td valign="top">
<%#Eval("Content")%>
</td>
</tr>
</table>
</td>
</ItemTemplate>
</asp:Repeater>
</tr>
</table>
Если важно разместить содержимое в таблице, вы можете "повернуть" свою таблицу в другую структуру и привязать ее к этой структуре. Или, если это не важно, что данные находятся в таблице, вы можете поместить элементы в div и поплавать ими, чтобы они были бок о бок.
Edit:
Здесь я имею в виду, вращая данные. Если ваши данные в настоящее время находятся в структуре типа List<MyDataClass>
, где MyDataClass определяется как нечто вроде:
class MyDataClass
{
public string Category { get; set; }
public string Content { get; set; }
public int OtherField { get; set; }
}
... тогда логический макет, когда итерация через структуру будет выглядеть так:
MyDataClass[0]: Category, Content, OtherField
MyDataClass[1]: Category, Content, OtherField
...
При вращении данных вы превращаете эти строки в столбцы и столбцы в строки. Например, вы можете заполнить код List<List<string>>
следующим кодом:
var rotated = new List<List<string>> {
new List<string>(), new List<string>(), new List<string>(),
};
for each (MyDataClass object in myCollection)
{
rotated[0].Add(object.Category);
rotated[1].Add(object.Content);
rotated[2].Add(object.OtherField.ToString("n0"));
}
Теперь ваша структура данных выглядит так:
rotated[0]: MyDataClass[0].Category, MyDataClass[1].Category, ...
rotated[1]: MyDataClass[0].Content, MyDataClass[1].Content, ...
rotated[2]: MyDataClass[0].OtherField, MyDataClass[1].OtherField, ...
В принципе, вы преобразуете данные в форму, которая может быть удалена прямо в вашу таблицу.
Изменить 2:
Мне действительно приходится делать подобные ротации для отчетов достаточно часто, чтобы я сделал метод расширения для IEnumerable, который будет делать поворот несколько более элегантным образом. Здесь метод расширения:
public static class MyCollectionExtensionMethods
{
public static IEnumerable<IEnumerable<TResult>> Rotate<TOrig, TResult>(
this IEnumerable<TOrig> collection,
params Func<TOrig, TResult>[] valueSelectors)
{
return valueSelectors.Select(s => collection.Select(i => s(i)));
}
}
И вот как я буду использовать его:
IEnumerable<IEnumerable<string>> rotated = data.Rotate(
i => i.Category, i => i.Content, i => i.OtherField.ToString("n0"))
Исправьте меня, если я неправильно понял, но мне кажется, что вы можете использовать только один повторитель, интегрируя свой первый ретранслятор в тег HeaderTeplate, а второй - в ItemTemplate.