Dynamically create HTML table in C#

前端 未结 4 1523
逝去的感伤
逝去的感伤 2020-12-30 06:40

Is there more efficient way to build HTML table than the one I\'m trying on right now?

I\'m getting an object and it has some list of entities in it. So I need to pa

相关标签:
4条回答
  • 2020-12-30 07:17

    As I've recently come to play with creating IDisposable classes, I think this would be both efficient for this specific task, and much easier to read:

    Create some very simple classes

        /// <summary>
        /// https://stackoverflow.com/a/36476600/2343
        /// </summary>
        public class Table : IDisposable
        {
            private StringBuilder _sb;
    
            public Table(StringBuilder sb, string id = "default", string classValue="")
            {
                _sb = sb;
                _sb.Append($"<table id=\"{id}\" class=\"{classValue}\">\n");
            }
    
            public void Dispose()
            {
                _sb.Append("</table>");
            }
    
            public Row AddRow()
            {
                return new Row(_sb);
            }
    
            public Row AddHeaderRow()
            {
                return new Row(_sb, true);
            }
    
            public void StartTableBody()
            {
                _sb.Append("<tbody>");
    
            }
    
            public void EndTableBody()
            {
                _sb.Append("</tbody>");
    
            }
        }
    
        public class Row : IDisposable
        {
            private StringBuilder _sb;
            private bool _isHeader;
            public Row(StringBuilder sb, bool isHeader = false)
            {
                _sb = sb;
                _isHeader = isHeader;
                if (_isHeader)
                {
                    _sb.Append("<thead>\n");
                }
                _sb.Append("\t<tr>\n");
            }
    
            public void Dispose()
            {
                _sb.Append("\t</tr>\n");
                if (_isHeader)
                {
                    _sb.Append("</thead>\n");
                }
            }
    
            public void AddCell(string innerText)
            {
                _sb.Append("\t\t<td>\n");
                _sb.Append("\t\t\t"+innerText);
                _sb.Append("\t\t</td>\n");
            }
        }
    }
    

    Then you can define your table using:

    StringBuilder sb = new StringBuilder();
    
    using (Html.Table table = new Html.Table(sb))
    {
        foreach (var invalidCompany in mailMessageObject.InvalidCompanies)
        {
            using (Html.Row row = table.AddRow())
            {
                row.AddCell(invalidCompany.BusinessName);
                row.AddCell(invalidCompany.SwiftBIC);
                row.AddCell(invalidCompany.IBAN);
            }
        }
    }
    
    string finishedTable = sb.ToString();
    
    0 讨论(0)
  • 2020-12-30 07:18

    It is a decent approach, and just 'what it takes' to output something as complicated as HTML - unless you want to do it using plain strings (which is just as messy, if not worse).

    One improvement: do not use the same cell object multiple times, you run the risk of getting incorrect output. Improved code:

    row.Cells.Add(new HtmlTableCell { InnerText = invalidCompany.BusinessName });
    row.Cells.Add(new HtmlTableCell { InnerText = invalidCompany.SwiftBIC });
    row.Cells.Add(new HtmlTableCell { InnerText = invalidCompany.IBAN });
    

    Of course you can also create your own helpers for creating cells, for creating a row full of cells, etc. There are also good libraries for this, e.g. see https://www.nuget.org/packages/HtmlTags/.

    0 讨论(0)
  • 2020-12-30 07:30

    I would just like to supplement Steve Harris' answer with a class library that is a little more built out. His answer is a totally elegant solution that made a windows service I was creating not have to reference System.Web for no good reason!

    Classes Defined:

      public static class Html
      {
        public class Table : HtmlBase, IDisposable
        {
          public Table(StringBuilder sb, string classAttributes = "", string id = "") : base(sb)
          {
            Append("<table");
            AddOptionalAttributes(classAttributes, id);
          }
    
          public void StartHead(string classAttributes = "", string id = "")
          {
            Append("<thead");
            AddOptionalAttributes(classAttributes, id);
          }
    
          public void EndHead()
          {
            Append("</thead>");
          }
    
          public void StartFoot(string classAttributes = "", string id = "")
          {
            Append("<tfoot");
            AddOptionalAttributes(classAttributes, id);
          }
    
          public void EndFoot()
          {
            Append("</tfoot>");
          }
    
          public void StartBody(string classAttributes = "", string id = "")
          {
            Append("<tbody");
            AddOptionalAttributes(classAttributes, id);
          }
    
          public void EndBody()
          {
            Append("</tbody>");
          }
    
          public void Dispose()
          {
            Append("</table>");
          }
    
          public Row AddRow(string classAttributes = "", string id = "")
          {
            return new Row(GetBuilder(), classAttributes, id);
          }
        }
    
        public class Row : HtmlBase, IDisposable
        {
          public Row(StringBuilder sb, string classAttributes = "", string id = "") : base(sb)
          {
            Append("<tr");
            AddOptionalAttributes(classAttributes, id);
          }
          public void Dispose()
          {
            Append("</tr>");
          }
          public void AddCell(string innerText, string classAttributes = "", string id = "", string colSpan = "")
          {
            Append("<td");
            AddOptionalAttributes(classAttributes, id, colSpan);
            Append(innerText);
            Append("</td>");
          }
        }
    
        public abstract class HtmlBase
        {
          private StringBuilder _sb;
    
          protected HtmlBase(StringBuilder sb)
          {
            _sb = sb;
          }
    
          public StringBuilder GetBuilder()
          {
            return _sb;
          }
    
          protected void Append(string toAppend)
          {
            _sb.Append(toAppend);
          }
    
          protected void AddOptionalAttributes(string className = "", string id = "", string colSpan = "")
          {
    
            if (!id.IsNullOrEmpty())
            {
              _sb.Append($" id=\"{id}\"");
            }
            if (!className.IsNullOrEmpty())
            {
              _sb.Append($" class=\"{className}\"");
            }
            if (!colSpan.IsNullOrEmpty())
            {
              _sb.Append($" colspan=\"{colSpan}\"");
            }
            _sb.Append(">");
          }
        }
      }
    

    Usage:

    StringBuilder sb = new StringBuilder();
          using (Html.Table table = new Html.Table(sb, id: "some-id"))
          {
            table.StartHead();
            using (var thead = table.AddRow())
            {
              thead.AddCell("Category Description");
              thead.AddCell("Item Description");
              thead.AddCell("Due Date");
              thead.AddCell("Amount Budgeted");
              thead.AddCell("Amount Remaining");
            }
            table.EndHead();
            table.StartBody();
            foreach (var alert in alertsForUser)
            {
              using (var tr = table.AddRow(classAttributes: "someattributes"))
              {
               tr.AddCell(alert.ExtendedInfo.CategoryDescription);
                tr.AddCell(alert.ExtendedInfo.ItemDescription);
                tr.AddCell(alert.ExtendedInfo.DueDate.ToShortDateString());
                tr.AddCell(alert.ExtendedInfo.AmountBudgeted.ToString("C"));
                tr.AddCell(alert.ExtendedInfo.ItemRemaining.ToString("C"));
              }
            }
            table.EndBody();
          }
          return sb.ToString();
    
    0 讨论(0)
  • 2020-12-30 07:36

    I think maybe you can add a function to get all the properties from your object. And then just iterate over them. Also you can create a list of properties that need to be displayed in your message.

        private static PropertyInfo[] GetProperties(object obj)
        {
            return obj.GetType().GetProperties();
        }
    
        // -------
        foreach (var invalidCompany in mailMessageObject.InvalidCompanies)
        {
            var properties = GetProperties(invalidCompany);     
            foreach (var p in properties)
            {   
                string name = p.Name;
                if(propertiesThatNeedToBeDisplayed.Contains(name)
                {
                    cell.InnerText = p.GetValue(invalidCompany, null);
                    row.Cells.Add(cell);
                    table.Rows.Add(row);
                }
            }
        }
    
    0 讨论(0)
提交回复
热议问题