我正在为使用.NET 4.0和IIS 7的客户端构建一个数据库编辑器/业务线工具。我想根据存储在Session中的值,有条件地在页面中包含一些HTML。我在服务器端执行此操作,为了封装代码,我创建了一个ASP服务器控件。
正如您将看到的,服务器控件生成的标记不是我所期望的。我希望有人以前见过这一点,并能帮助我理解如何控制标记生成输出。
以下是名为MyList的控件的新RenderContent。它应该使用<李>标签
protected override void RenderContents(HtmlTextWriter output) {
output.RenderBeginTag(HtmlTextWriterTag.Li);
output.WriteEncodedText(this.Text);
output.RenderEndTag();
}
在编译了主项目并添加了对MyList的引用之后,我在以下HTML中使用MyList:
<h1>Favorite Things</h1>
<ul>
<cc1:MyList ID="mL1" runat="server" Text="Code that works!" />
<cc1:MyList ID="mL2" runat="server" Text="Going home before 8" />
<cc1:MyList ID="mL3" runat="server" Text="Cold drinks in fridge" />
</ul>
它生成以下内容:
<h1>Favorite Things</h1>
<ul>
<span id="MainContent_mL1"><li>Code that works!</li></span>
<span id="MainContent_mL2"><li>Going home before 8</li></span>
<span id="MainContent_mL3"><li>Cold drinks in fridge</li></span>
</ul>
现在我添加了一个基于Session值的测试。WebControl的Page属性为我提供了对控件容器的引用,从而访问我的会话:
protected override void RenderContents(HtmlTextWriter output) {
string backcolor = "Yellow";
if (this.Page.Session["access"] == null) {
backcolor = "Red";
}
output.RenderBeginTag(HtmlTextWriterTag.Li);
output.AddStyleAttribute(HtmlTextWriterStyle.BackgroundColor, backcolor);
output.WriteEncodedText(this.Text);
output.RenderEndTag();
}
现在,标记开始瓦解。注意"mL1"中的不一致性:
<h1>Favorite Things</h1>
<ul>
<span id="MainContent_mL1"><li>Code that works!</li></span>
<span id="MainContent_mL2" style="background-color:Red;"><li>Going home before 8</li></span>
<span id="MainContent_mL3" style="background-color:Red;"><li>Cold drinks in fridge</li></span>
</ul>
在我更复杂的真实代码中,标记变成了span
标记。而且,当我在RenderContents()
中设置断点时,当我一行有五个标记时,它只被调用一次。
其他信息:带有cc1:MyList控件的页面的EnableSession=true。我的web.config指定了正常的会话管理器('rml'和'RoleBasedList'指的是我的'real'控件,我简化了它以隔离问题并缩短这篇文章):
<system.web>
<trace enabled="true" localOnly="false" pageOutput="true" requestLimit="20" />
<compilation debug="true" targetFramework="4.0" />
<pages>
<controls>
<add tagPrefix="rml" assembly="RoleBasedList" namespace="SOTS.ServerControls"/>
</controls>
</pages>
<httpModules>
<add name="Session" type="System.Web.SessionState.SessionStateModule"/>
</httpModules>
<sessionState mode="InProc" cookieless="false" timeout="60"/>
...
</system.web>
现在你知道我所做的一切了!
您只需要覆盖自定义服务器控件中的WebControl.TagKey
属性:
protected override HtmlTextWriterTag TagKey
{
get { return HtmlTextWriterTag.Li; }
}
默认值为Span
,它解释了您所看到的内容。当然,如果这样做,就不会在RenderContents
覆盖中呈现Li标记。
另一种选择是覆盖Render
,完全控制渲染,或者从Control
派生。但您将失去WebControl
的一些功能,尤其是外部标签的样式。
关于您的第二个问题,您正在致电:
output.AddStyleAttribute(HtmlTextWriterStyle.BackgroundColor, backcolor);
其向CCD_ 9添加要应用于下一次调用的样式属性。您不调用RenderBeginTag
,因此这将应用于树中下一个控件中的标记。
另一点是,当控件在Visual Studio设计器中呈现时,Session
将为null。你应该检查null,或者检查你是否在设计模式下运行:
if ((Site != null) && (Site.DesignMode))
{
... running in design mode, Session won't be available
}
避免System.Web.UI.WebControls
。我建议您直接将System.Web.UI.Control
划分为子类。
<span>
是由您派生的类插入的(您没有提到)。请注意,您覆盖的是RenderContents
而不是Render
,这意味着控件超类可以自由地用它想要的任何内容包装RenderContents
的输出,在本例中为<span>
。