我在客户端生成了一个HTML行(<tr>
),我想转换包含HtmlTableRow
控件中的行单元格信息的字符串。到目前为止,我使用Convert string to WebControls - asp.net上的示例完成了这项工作。感谢
string row = "<tr><td>item</td><td><input name=\"radio0\" type=\"radio\"/></td></tr>";
Dictionary<string, HtmlContainerControl> controlConstructor = new Dictionary<string, HtmlContainerControl>
{
{"tr", new HtmlTableRow()},
{"td", new HtmlTableCell()}
};
var htmlDoc = XElement.Parse(row);
Func<XElement, HtmlControl> constructHtmlStructure = null;
constructHtmlStructure = (o =>
{
var control = controlConstructor[o.Name.ToString()];
if (o.HasElements)
{
control.Controls.Add(constructHtmlStructure(o.Elements().Single())); //Exception: Sequence contains more than one element (When is a input item)
}
else
{
control.InnerText = o.Value;
}
return control;
});
HtmlTableRow structure = (HtmlTableRow)constructHtmlStructure(htmlDoc);
答案 0 :(得分:1)
为什么不使用更简单的方法将字符串解析为HtmlTableRow。
您的Dictionary<string, HtmlContainerControl> controlConstructor
仅考虑tr
和td
,嵌入其中的输入控件怎么样?
所以即使你通过“sequence contains more than one element
”,使用foreach循环,你也会收到错误"key doesn't exist
“。
即使您管理克服了(通过在词典中添加输入键),也无法将其解析为HtmlContainerControl
。
即使您这样做,通过将Dictionary<string, HtmlContainerControl>
更新为Dictionary<string, HtmlControl>
,您也必须考虑处理该输入控件的方法,因为为此您无法control.InnerText = o.value;
因此更简单:
string row = "<tr><td>item</td><td><input name=\"radio0\" type=\"radio\"/></td></tr>";
XmlDocument doc = new XmlDocument();
doc.LoadXml(row);
HtmlTableRow tblRow = new HtmlTableRow();
foreach (XmlNode node in doc.SelectSingleNode("tr").ChildNodes)
{
HtmlTableCell cell = new HtmlTableCell();
cell.InnerText = node.InnerXml;
foreach (XmlNode childNode in node.ChildNodes)
{
if (childNode.Name == "input")
{
if (childNode.Attributes["type"] != null)
{
switch (childNode.Attributes["type"].Value.ToString())
{
case "radio":
HtmlInputRadioButton rad = new HtmlInputRadioButton();
rad.Name = childNode.Attributes["name"].ToString();
cell.Controls.Add(rad);
break;
///other types of input controls
default:
break;
}
}
else
{
HtmlInputButton button = new HtmlInputButton("button");
cell.Controls.Add(button);
}
}
}
tblRow.Cells.Add(cell);
}
正如您所看到的,这是一个非常粗略和严格的逻辑:您可以做的最好的事情是提出一个递归函数,来构建您的HtmlTableRow
答案 1 :(得分:0)
Linq的Single
方法返回序列的第一个也是唯一的元素 - 如果有多个元素则会抛出您看到的异常。由于您的表格行包含两个表格单元格,因此其o.Elements()
方法会返回一个包含两个成员的枚举,并使用Single
使其失效。
而不是使用:
control.Controls.Add(constructHtmlStructure(o.Elements().Single()));
...使用:
foreach(var element in o.Elements())
{
control.Controls.Add(constructHtmlStructure(element));
}
这样,您遍历每个表行的单元格,并将每个单元格添加到控件中。
修改强>
你需要做出另一个改变。您的字典中只包含一个HtmlTableRow
和一个HtmlTableRow
,两者都是在您进入constructHtmlStructure
时创建的。您应该让词典按需创建每种类型的新实例,而不是预先存在的对象(因此只有每个可用的实例)。
所以不是这个(调整间距):
var controlConstructor = new Dictionary<string, HtmlContainerControl>
{
{ "tr", new HtmlTableRow() },
{ "td", new HtmlTableCell() }
};
...
var control = controlConstructor[o.Name.ToString()];
...试试这个:
var controlConstructor = new Dictionary<string, Func<XElement, HtmlControl>>
{
{ "tr", o => new HtmlTableRow() },
{ "td", o => new HtmlTableCell() }
};
...
var control = controlConstructor[o.Name.ToString()].Invoke(o);
您还需要一个函数来创建XElement
的输入,如下所示:
private static HtmlControl CreateInputFromElement(XElement element)
{
// Create an appropriate HtmlInputControl...
}
...您可以像这样添加到词典中:
var controlConstructor = new Dictionary<string, Func<XElement, HtmlControl>>
{
{ "tr", o => new HtmlTableRow() },
{ "td", o => new HtmlTableCell() },
{ "input", CreateInputFromElement }
};