在我看来,使用 HtmlTextWriter 呈现 HTML 并不是非常直观,但如果您在 Web 表单中实现 Web 控件,则必须使用它。我认为有可能为此创建一个流畅的界面,该界面看起来更像它输出的 HTML。我想知道人们对我迄今为止提出的语法的看法。
public void Render(HtmlTextWriter writer)
{
writer
.Tag(HtmlTextWriterTag.Div, e => e[HtmlTextWriterAttribute.Id, "id"][HtmlTextWriterAttribute.Name,"name"][HtmlTextWriterAttribute.Class,"class"])
.Tag(HtmlTextWriterTag.Span)
.Text("Lorem")
.EndTag()
.Tag(HtmlTextWriterTag.Span)
.Text("ipsum")
.EndTag()
.EndTag();
}
“Tag”、“Text”和“EndTag”是 HtmlTextWriter 类的扩展方法,它们返回它接收的实例,以便可以链接调用。第一次调用“Tag”使用的重载中使用的传递给 lambda 的参数是一个“HtmlAttributeManager”,它是一个简单的类,它包装了一个 HtmlTextWriter 以提供一个索引器,该索引器接受一个 HtmlTextWriterAttribute 和一个字符串值并返回实例,所以可以链接调用。我还为这个类提供了最常见属性的方法,例如“Name”、“Class”和“Id”,这样您就可以将上面的第一个调用编写如下:
.Tag(HtmlTextWriterTag.Div, e => e.Id("id").Name("name").Class("class"))
再长一点的例子:
public void Render(HtmlTextWriter writer)
{
writer
.Tag(HtmlTextWriterTag.Div, a => a.Class("someClass", "someOtherClass"))
.Tag(HtmlTextWriterTag.H1).Text("Lorem").EndTag()
.Tag(HtmlTextWriterTag.Select, t => t.Id("fooSelect").Name("fooSelect").Class("selectClass"))
.Tag(HtmlTextWriterTag.Option, t => t[HtmlTextWriterAttribute.Value, "1"][HtmlTextWriterAttribute.Title, "Selects the number 1."])
.Text("1")
.EndTag(HtmlTextWriterTag.Option)
.Tag(HtmlTextWriterTag.Option, t => t[HtmlTextWriterAttribute.Value, "2"][HtmlTextWriterAttribute.Title, "Selects the number 2."])
.Text("2")
.EndTag(HtmlTextWriterTag.Option)
.Tag(HtmlTextWriterTag.Option, t => t[HtmlTextWriterAttribute.Value, "3"][HtmlTextWriterAttribute.Title, "Selects the number 3."])
.Text("3")
.EndTag(HtmlTextWriterTag.Option)
.EndTag(HtmlTextWriterTag.Select)
.EndTag(HtmlTextWriterTag.Div);
}
希望您能够“破译”此代码段输出的 HTML,至少是这样的想法。
请给我任何关于如何改进语法的想法,也许是更好的方法名称,也许是其他一些方法。
编辑:我认为在不使用流畅界面的情况下查看相同的代码段可能会很有趣,以进行比较:
public void RenderUsingHtmlTextWriterStandardMethods(HtmlTextWriter writer)
{
writer.AddAttribute(HtmlTextWriterAttribute.Class, "someClass someOtherClass");
writer.RenderBeginTag(HtmlTextWriterTag.Div);
writer.RenderBeginTag(HtmlTextWriterTag.H1);
writer.Write("Lorem");
writer.RenderEndTag();
writer.AddAttribute(HtmlTextWriterAttribute.Id, "fooSelect");
writer.AddAttribute(HtmlTextWriterAttribute.Name, "fooSelect");
writer.AddAttribute(HtmlTextWriterAttribute.Class, "selectClass");
writer.RenderBeginTag(HtmlTextWriterTag.Select);
writer.AddAttribute(HtmlTextWriterAttribute.Value, "1");
writer.AddAttribute(HtmlTextWriterAttribute.Title, "Selects the number 1.");
writer.RenderBeginTag(HtmlTextWriterTag.Option);
writer.Write("1");
writer.RenderEndTag();
writer.AddAttribute(HtmlTextWriterAttribute.Value, "2");
writer.AddAttribute(HtmlTextWriterAttribute.Title, "Selects the number 2.");
writer.RenderBeginTag(HtmlTextWriterTag.Option);
writer.Write("2");
writer.RenderEndTag();
writer.AddAttribute(HtmlTextWriterAttribute.Value, "3");
writer.AddAttribute(HtmlTextWriterAttribute.Title, "Selects the number 3.");
writer.RenderBeginTag(HtmlTextWriterTag.Option);
writer.Write("3");
writer.RenderEndTag();
writer.RenderEndTag();
writer.RenderEndTag();
}
编辑:我可能应该更明确一点,其中一个目标是它应该产生尽可能少的开销,这就是我限制使用 lambdas 的原因。同样,起初我使用了一个表示标签的类,以便在渲染之前通过语法构建类似于 DOM 树的东西,尽管语法非常相似。我放弃了这个解决方案,因为它会产生轻微的内存开销。在使用 HtmlAttributeManager 类时仍然存在一些这种情况,我一直在考虑使用扩展方法来附加属性,但是我不能使用 indexer-syntax,而且它会使 HtmlTextWriter 的接口膨胀更。