I find the TagBuilder written in C# little poor without the ability to "host" inside it sub tags (as objects not as strings).
So I wrote a simple class that inherits TagBuilder and allow to save sub tags. I can navigate inside it and add things to it while I move across the application. And when I call the Top Tag Object .ToString, it will render the entire html
public class MultiLevelHtmlTag : TagBuilder
{
public MultiLevelHtmlTag(string tagName) : base(tagName) { }
public List<MultiLevelHtmlTag> InnerTags = new List<MultiLevelHtmlTag>();
public override string ToString()
{
if (InnerTags.Count > 0)
{
foreach (MultiLevelHtmlTag tag in InnerTags)
{
this.InnerHtml += tag.ToString();
}
}
return base.ToString();
}
}
this is how I use it:
MultiLevelHtmlTag top = new MultiLevelHtmlTag("div");
top.InnerTags.Add(new MultiLevelHtmlTag("span"));
log.Debug(top.ToString());
output:
<div><span></span></div>
What do you think about it? is that a goot pattern?
1 Answer 1
I would make sure the list is not exposed publicly - the caller can then do whatever they want with that list, even assign null
to it. So I've refactored it a little bit and implemented Add()
(you may also want to implement Remove()
, etc.):
/// <summary>
/// Simple class that inherits TagBuilder and allow to save sub tags.
/// </summary>
public class MultiLevelHtmlTag : TagBuilder
{
/// <summary>
/// List of inner tags.
/// </summary>
private readonly IList<MultiLevelHtmlTag> innerTags = new List<MultiLevelHtmlTag>();
/// <summary>
/// Initializes a new instance of the <see cref="MultiLevelHtmlTag"/> class.
/// </summary>
/// <param name="tagName">The name of the tag.</param>
public MultiLevelHtmlTag(string tagName) : base(tagName)
{
}
/// <summary>
/// Gets the inner tag list.
/// </summary>
/// <value>The inner tag list.</value>
public IEnumerable<MultiLevelHtmlTag> InnerTags
{
get
{
return new ReadOnlyCollection<MultiLevelHtmlTag>(this.innerTags);
}
}
/// <summary>
/// Adds the specified tag to the inner tag list.
/// </summary>
/// <param name="tag">The tag to add.</param>
public void Add(MultiLevelHtmlTag tag)
{
if (tag == null)
{
throw new ArgumentNullException("tag");
}
this.innerTags.Add(tag);
}
/// <summary>
/// Returns a <see cref="System.String"/> that represents this instance.
/// </summary>
/// <returns>
/// A <see cref="System.String"/> that represents this instance.
/// </returns>
public override string ToString()
{
var sb = new StringBuilder();
foreach (var tag in this.innerTags)
{
sb.Append(tag.ToString());
}
this.InnerHtml = sb.ToString();
return base.ToString();
}
}
-
\$\begingroup\$ Great response; in my project I've just changed the inner tags to be
TagBuilder
(so that I can add "regular"TagBuilder
objects to it); there's no actual need to have them asMultiLevelHtmlTag
s. \$\endgroup\$Marcel Popescu– Marcel Popescu2013年07月07日 06:39:09 +00:00Commented Jul 7, 2013 at 6:39 -
\$\begingroup\$ @ANeves - you need to use concat your results to the existing inner text or else you will end up with all empty tags. \$\endgroup\$Leonardo Herrera– Leonardo Herrera2014年06月12日 21:57:54 +00:00Commented Jun 12, 2014 at 21:57
ToString()
method has some major problems. See what happens if you call it multiple times. It should only return a string representation of the object. It shouldn't be modifying it. \$\endgroup\$