问题描述
我正在以编程方式在中继器中创建一个表.我的问题是项目模板部分中的单元格无法正确呈现.它们在表格标记后显示为文本节点.有人对如何正确呈现表格单元格有任何建议吗?
I'm creating a table inside a repeater programmatically. My problem is that the cells in the item template part don't render properly. They are showing up as text nodes after the table's markup. Does anyone have any suggestions on how to get the table cells rendering properly?
using System;
using System.Collections.Generic;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
namespace WebApplication1
{
public partial class WebForm2 : Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
var dogs = new List<Dog>
{
new Dog { Name = "Rex", Breed = "Russell Terrier" },
new Dog { Name = "Fido", Breed = "Poodle" },
new Dog { Name = "Fetcher", Breed = "Golden Retriever" },
};
var repeater = new Repeater { ID = "Repeater1" };
repeater.DataSource = dogs;
repeater.DataBind();
AddHeader(repeater);
AddItems(repeater, dogs);
PlaceHolder1.Controls.Add(repeater);
}
}
private void AddHeader(Repeater repeater)
{
var repeaterItem = new RepeaterItem(0, ListItemType.Header);
var table = new HtmlTable();
var row = new HtmlTableRow();
var cell1 = new HtmlTableCell("th") { InnerText = "Name" };
var cell2 = new HtmlTableCell("th") { InnerText = "Breed" };
row.Cells.Add(cell1);
row.Cells.Add(cell2);
table.Rows.Add(row);
repeaterItem.Controls.Add(table);
repeater.Controls.Add(repeaterItem);
}
private void AddItems(Repeater repeater, List<Dog> dogs)
{
for (var i = 0; i < repeater.Items.Count; i++)
{
var repeaterItem = new RepeaterItem(i + 1, ListItemType.Item);
var row = new HtmlTableRow();
var cell1 = new HtmlTableCell() { InnerText = dogs[i].Name };
var cell2 = new HtmlTableCell() { InnerText = dogs[i].Breed };
row.Cells.Add(cell1);
row.Cells.Add(cell2);
repeaterItem.Controls.Add(row);
repeater.Controls.Add(repeaterItem);
}
}
private sealed class Dog
{
public string Breed { get; set; }
public string Name { get; set; }
}
}
}
更新:多亏了 Rob 的帮助,我才能使代码正常工作.现在我有一个功能齐全的中继器,它完全加载在带有数据绑定的代码隐藏中.不错!
UPDATE: Thanks to Rob's help, I was able to get the code working. Now I have a fully-functional Repeater being loaded entirely in the code-behind with data-binding. Nice!
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using ExtensionMethods.WebControls;
namespace WebApplication1
{
public partial class WebForm1 : Page
{
protected void Page_Load(object sender, EventArgs e)
{
var dogs = new List<Dog>
{
new Dog { Name = "Rex", Breed = "Russell Terrier" },
new Dog { Name = "Fido", Breed = "Poodle" },
new Dog { Name = "Fetcher", Breed = "Golden Retriever" },
};
var repeater = new Repeater
{
ID = "Repeater1",
HeaderTemplate = new CustomTemplate(ListItemType.Header),
ItemTemplate = new CustomTemplate(ListItemType.Item),
FooterTemplate = new CustomTemplate(ListItemType.Footer),
DataSource = dogs
};
repeater.DataBind();
PlaceHolder1.Controls.Add(repeater);
}
// Custom template class to add controls to the repeater's header, item and footer sections.
private sealed class CustomTemplate : ITemplate
{
private ListItemType ListItemType { get; set; }
public CustomTemplate(ListItemType type)
{
ListItemType = type;
}
public void InstantiateIn(Control container)
{
if (ListItemType == ListItemType.Header)
{
var table = new LiteralControl();
var head = new HtmlGenericControl("thead");
var row = new HtmlTableRow();
row.Cells.Add(new HtmlTableCell("th") { InnerText = "Breed" });
row.Cells.Add(new HtmlTableCell("th") { InnerText = "Name" });
head.Controls.Add(row);
table.Text = string.Format("<table>{0}<tbody>", head.RenderHtml());
container.Controls.Add(table);
}
else if (ListItemType == ListItemType.Item)
{
var row = new HtmlTableRow();
var cell1 = new HtmlTableCell();
cell1.Controls.Add(new Literal { ID = "LiteralBreed" });
row.Cells.Add(cell1);
var cell2 = new HtmlTableCell();
cell2.Controls.Add(new Literal { ID = "LiteralName" });
row.Cells.Add(cell2);
container.Controls.Add(row);
container.DataBinding += new EventHandler(Container_DataBinding);
}
else if (ListItemType == ListItemType.Footer)
{
var footer = new LiteralControl("</tbody></table>");
container.Controls.Add(footer);
}
}
// Event handler to populate the dog's breed and name in the table when data-binding occurs.
private void Container_DataBinding(object sender, EventArgs e)
{
var item = sender as RepeaterItem;
if (item != null)
{
var dog = ((Dog)item.DataItem);
var breed = item.FindDescendantsByType<Literal>().Single(x => x.ID == "LiteralBreed");
breed.Text = dog.Breed;
var name = item.FindDescendantsByType<Literal>().Single(x => x.ID == "LiteralName");
name.Text = dog.Name;
}
}
}
private sealed class Dog
{
public string Breed { get; set; }
public string Name { get; set; }
}
}
}
推荐答案
那是因为在您的逻辑中,您要在 AddHeader 方法中创建一个带有标题的表并将其添加到转发器,这将创建:
That's because in your logic you are creating a table with a header in the AddHeader method and adding it to the repeater, that will create:
<table>
<tbody><tr>
<th>Name</th>
<th>Breed</th>
</tr></tbody>
</table>
然后将列表项添加到转发器,是转发器,而不是第一个表.您将表格行添加到表格后的中继器中,浏览器会将这些行和单元格呈现为文本节点,因为它们没有父 tbody 表格元素.
Then you add the list items to the repeater, yes to the repeater, not to the first table. You are adding table rows to the repeader after the table, and the browser will render this rows and cells as just text nodes because they don't have their parent tbody table elements.
repeater 编写 HTML,所以你需要找到一种方法来拥有打开和关闭 table 标签
The repeater writes HTML so you need to find a way to have the open and close table tags
<table>
<tbody>
<asp:Repeater ID="fooRepeater" runat="server" ></asp:Repeater>
</tbody>
</table>
因此中继器渲染将类似于:雷克斯罗素梗对于每个项目
So the repeater render will be something like: RexRussell Terrier For each item
如果您希望转发器中的每个项目都作为表格,我认为您的逻辑是错误的,您需要像这样更改代码:
I believe your logic is wrong if you want each item in the repeater as a table you need to change your code like this:
private void AddItems(Repeater repeater, List<Dog> dogs)
{
var repeaterItem = new RepeaterItem(0, ListItemType.Header);
var table = new HtmlTable();
var row = new HtmlTableRow();
var cell1 = new HtmlTableCell("th") { InnerText = "Name" };
var cell2 = new HtmlTableCell("th") { InnerText = "Breed" };
row.Cells.Add(cell1);
row.Cells.Add(cell2);
table.Rows.Add(row);
for (var i = 0; i < repeater.Items.Count; i++)
{
repeaterItem = new RepeaterItem(i + 1, ListItemType.Item);
row = new HtmlTableRow();
cell1 = new HtmlTableCell() { InnerText = dogs[i].Name };
cell2 = new HtmlTableCell() { InnerText = dogs[i].Breed };
row.Cells.Add(cell1);
row.Cells.Add(cell2);
table.Rows.Add(row);
}
repeaterItem.Controls.Add(table);
repeater.Controls.Add(repeaterItem);
}
一切都将在 AddItems 方法中发生,您不再需要 AddHeader.如果您希望每个转发器项目都是表格的行,则逻辑必须不同.
Everything will happen in the AddItems method and you no longer need the AddHeader. If you want each repeater item be the row of a table the logic must be different.
这篇关于使用动态绑定到对象列表的 ASP.NET 中继器创建 HtmlTable的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!