2013-03-02 71 views
2

我有一个客户端生成的HTML行(<tr>),我想转换包含HtmlTableRow控件中的行单元格信息的字符串。这是我迄今为止使用Convert string to WebControls - asp.net上的示例完成的。由于将字符串转换为HtmlTableRow控件

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

的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 } 
}; 
+0

感谢您的评论!但是..它不起作用structure.Cells.Count只返回1它可能是2 – christiangobo 2013-03-02 21:30:56

+0

不知道我跟着你 - 如果抛出异常,你如何调用'structure.Cells.Count'?你问题中的HTML是一个包含两个'td'的'tr';所以第一次执行'constructHtmlStructure','o'('tr')'.Elements()'('td's)将返回两个元素。这就是为什么'Single()'抛出它所做的错误。 – 2013-03-02 22:33:27

+0

我做了你提出的改变和structure.Cells.Count返回1时,在字符串中的每个​​是1个单元 – christiangobo 2013-03-02 22:57:41

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

+0

感谢您的时间。几乎完成了,但我需要将输入控件投射到一个对象 – christiangobo 2013-03-02 21:32:28

+0

中,您将不得不检测它,因为没有其他自动方法。更新我的答案 – 2013-03-02 21:34:19