当我在ASP.net中生成控件时,他们会这样出来:
<div id="ctl00_mainContent_ApprovalSelectPanel" class="discussWrapper">
<span class="cbox highlighted"><input id="ctl00_mainContent_ctl00" type="checkbox" name="ctl00$mainContent$ctl00" checked="checked" value="70" /><label for="ctl00_mainContent_ctl00">Buyer1</label></span><span class="cbox"><input id="ctl00_mainContent_ctl01" type="checkbox" name="ctl00$mainContent$ctl01" value="75" /><label for="ctl00_mainContent_ctl01">Buyer2</label></span><span class="cbox"><input id="ctl00_mainContent_ctl02" type="checkbox" name="ctl00$mainContent$ctl02" value="280" /><label for="ctl00_mainContent_ctl02">Client3</label></span><span class="cbox"><input id="ctl00_mainContent_ctl03" type="checkbox" name="ctl00$mainContent$ctl03" value="281" /><label for="ctl00_mainContent_ctl03">Client4</label></span><span class="cbox"><input id="ctl00_mainContent_ctl04" type="checkbox" name="ctl00$mainContent$ctl04" value="283" /><label for="ctl00_mainContent_ctl04">Client2</label></span><span class="cbox"><input id="ctl00_mainContent_ctl05" type="checkbox" name="ctl00$mainContent$ctl05" value="289" /><label for="ctl00_mainContent_ctl05">Client1</label></span><span class="cbox"><input id="ctl00_mainContent_ctl06" type="checkbox" name="ctl00$mainContent$ctl06" value="346" /><label for="ctl00_mainContent_ctl06">artworker1</label></span><span class="cbox"><input id="ctl00_mainContent_ctl07" type="checkbox" name="ctl00$mainContent$ctl07" value="362" /><label for="ctl00_mainContent_ctl07">buyer3</label></span><span class="cbox"><input id="ctl00_mainContent_ctl08" type="checkbox" name="ctl00$mainContent$ctl08" value="367" /><label for="ctl00_mainContent_ctl08">meeeee</label></span><span class="cbox"><input id="ctl00_mainContent_ctl09" type="checkbox" name="ctl00$mainContent$ctl09" value="368" /><label for="ctl00_mainContent_ctl09">stake</label></span>
</div>
查看源代码时非常难看且难以理解。这通常不是问题,但我的网站正在为访问者提供资源和教程,其中查看源是体验的一部分。
有没有办法很好地渲染这些控件?正确缩进,更好的ID和名称等?
答案 0 :(得分:14)
在.NET 4.0中,您可以将ClientIDMode设置为4个选项之一AutoID,Static,Predictable和Inherit。您可能正在寻找静态,因为这将确保您的控件呈现给包含您已分配给它们的ID的页面。
您可以通过添加以下内容在应用程序级别设置:
<pages clientIDMode="Static">
到你的web.config
这里有关于这些更改的更多详细信息:http://beyondrelational.com/blogs/hima/archive/2010/07/16/all-about-client-id-mode-in-asp-net-4.aspx
答案 1 :(得分:6)
ASP.NET WebForms HTML呈现和控制标记在.NET 4.0中得到了改进,这将有助于控制ID和HTML元素本身的结构(如Rob Stone's answer中提到的那样)。但是,缩进和换行可能仍然不能满足您的需求。
如果HTML源真正是您的应用程序的用户体验的一部分,您可能考虑编写附加到ReleaseRequestState事件的HttpModule 。此方法将解决HTML源的实际换行符和缩进。要 avoid re-inventing the wheel ,您可以在响应中使用.NET port of HTML Tidy或.NET Wrapper for HTML Tidy作为自定义过滤器的一部分。
有一个很好的例子,说明如何在this blog中的HttpModule中编写自定义过滤器。我发现最有用的代码部分如下(稍加编辑,但您可以从博客本身获得完整的理解):
public class CustomModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.ReleaseRequestState += new EventHandler(context_ReleaseRequestState);
}
private void context_ReleaseRequestState(object sender, EventArgs e)
{
HttpResponse response = HttpContext.Current.Response;
if (string.Compare(response.ContentType,"text/html",true) == 0)
{
response.Filter = new CustomFilter(response.Filter,response.ContentEncoding);
}
}
}
并在CustomFilter类中...
public override void Write(byte[] buffer, int offset, int count)
{
sb = new StringBuilder(count + 1024);
sb.Append(enc.GetString(buffer,offset,count));
// <---- Run the sb content through HTML Tidy here ---->
byte[] buff = enc.GetBytes(sb.ToString());
s.Write(buff,0,buff.Length);
}
}
答案 2 :(得分:2)
获得漂亮的输出几乎是不可能的,因为解析器在渲染控件时没有任何上下文概念。许多控件呈现多个HTML元素,并且需要知道它们的上下文才能执行此操作...以及能够知道所需的格式(例如,对于列表控件,何时开始新行,何时再次缩进)。
此外,并非标记中的所有元素都实际呈现,并且标记的布局并不总是与输出的布局直接相关。例如:
<asp:PlaceHolder runat="server" />
<asp:Panel runat="server" />
<asp:DropDownList runat="server" />
</asp:Panel />
</asp:PlaceHolder />
Placeholder
未呈现,那么会导致输出中的缩进吗? DropDownList
呈现多个HTML控件,并且无法确定所需的呈现方式:它是否应缩进到与第一个控件相同的级别?它应该渲染没有元素间距?从实际的角度来看,渲染效率更高(没有大多数控件所做的),以最大限度地减少需要发送到客户端的数据量。
最后,即使在简单的情况下,当您从浏览器“查看源代码”时的实际表示在浏览器之间可能会有所不同。他们都可以选择以任何方式处理间距,换行符,缩进,因为元素间距不会以任何方式影响渲染。
如果您在网站上显示“之前/之后”示例,除了手动格式化输出以进行演示之外,您实际上没有太多选择,如果这是您想要的。如果人们也想查看源代码,那很好,但是让源代码始终看起来与标记一样好是非常具有挑战性的。
如果这对您来说非常重要,您可以拦截输出流并在发送到客户端之前重新格式化,但不会直接从asp.net的渲染引擎发生。有关如何执行此操作的示例,请参阅Google“asp.net响应过滤器” - here's one.我确信找到可以应用于此概念的HTML格式的代码并不难。
答案 3 :(得分:1)
来到这里的晚会,但我遇到了类似的问题。我们正在生成一些高度复杂的javascript,这些javascript变得过于混乱而无法合理调试,所有这些都与标记的其余部分混杂在一起。所以我想出了这堂课。
public class HtmlPrettyControl : HtmlGenericControl
{
public bool Indent { get; set; }
public HtmlPrettyControl(string tag) : this(tag, true) { }
public HtmlPrettyControl(string tag, bool indent) : base(tag)
{
Indent = indent;
}
protected override void Render(HtmlTextWriter writer)
{
// Here you can check if you are running against a production environment
// and just do base.Render to prevent extra code execution and space in
// your response to the client
if (Indent)
{
RenderBeginTag(writer);
writer.WriteLine();
writer.Indent++;
base.RenderChildren(writer);
writer.WriteLine();
writer.Indent--;
RenderEndTag(writer);
}
else
{
base.Render(writer);
}
writer.WriteLine();
}
}
用法示例:
var myDiv = new HtmlPrettyControl("div");
var myLabel = new HtmlPrettyControl("label", false);
myLabel.InnerText = "I'm sorry, Dave.";
myDiv.Controls.Add(myLabel)
生成标记:
<div>
<label>I'm sorry, Dave.</label>
<div>
对于不是简单Html标记的控件(在不同的基类/继承链中),我们使用类似的Render方法覆盖。唯一的缺点是传递给writer
方法的Render
似乎没有被告知您的控件所存在的ascx的当前缩进级别(如果有的话)。因此,虽然控件及其子代的层次结构很好地缩进和分解,但它们将重置为0的缩进级别,从而打破了ascx或aspx布局文件中环绕标记的整体流程。