2

<tr>在客户端生成了一个 HTML 行 (),我想转换包含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);
4

2 回答 2

1

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

Dictionary<string, HtmlContainerControl> controlConstructor 只考虑trtd,嵌套在其中的输入控件呢?

所以即使你通过那个“ sequence contains more than one element”,使用foreach循环,你也会得到一个错误"key doesn't exist“。

即使您设法克服了这一点(通过在字典中添加输入键),您也无法将其解析为HtmlContainerControl.

即使你这样做了,通过更新你的Dictionary<string, HtmlContainerControl>to 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

于 2013-03-02T21:23:42.800 回答
0

Linq 的Single方法返回序列的第一个也是唯一一个元素 - 如果有多个元素,它会抛出您看到的异常。由于您的表格行包含两个表格单元格,它的o.Elements()方法返回一个具有两个成员的可枚举,并且 usingSingle使它翻倒。

而不是使用:

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 }
};
于 2013-03-02T21:13:51.333 回答