将字符串转换为HtmlTableRow控件

时间:2013-03-02 20:24:58

标签: c# asp.net asp.net-webcontrol

我在客户端生成了一个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);

2 个答案:

答案 0 :(得分:1)

为什么不使用更简单的方法将字符串解析为HtmlTableRow。

您的Dictionary<string, HtmlContainerControl> controlConstructor仅考虑trtd,嵌入其中的输入控件怎么样?

所以即使你通过“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 }
};