我需要开发一个类似模板的用户控件,它可以接受任意内容,包括其他控件。
WmlCard.ascx
<asp:PlaceHolder ID="phContent" runat="server">
<card id="<%= Me.CardId %>" title="<%= Me.Title %>">
<p>
<%= Me.InnerText %>
</p>
</card>
</asp:PlaceHolder>
它将以这种方式使用:
的 ListaTelefonica.aspx
<%@ Register TagPrefix="sic" TagName="Card" Src="~/path/to/WmlCard.ascx"%>
<sic:Card ID="BuscaCard" runat="server" CardId="busca" title="Lista Telefônica" Visible="false">
<asp:Literal ID="SomeLiteral" runat="server" Visible="false">Some text<br /></asp:Literal>
<asp:Literal ID="RuntimeFilledLiteral" runat="server" Visible="false" /><br /></asp:Literal>
Any text.
</sic:Card>
不幸的是,Ascx用户控件必须继承System.Web.UI.UserControl
。例如,如果我可以继承System.Web.UI.WebControls.WebControl
,那将是一件小事。
我的问题类似于to this one,但是控件不应该只是文本,而是应该接受其中的任何其他控件。
我在<ParseChildren(False)>
中尝试AddParsedSubObject(Object)
并覆盖WmlCard
,但它不是解决方案,因为html在页面加载之前呈现,因此更改{{{}的值毫无意义1}}在页面的Page_Load中,例如。
我得到的第一个错误:
分析器错误消息:类型'ASP.sic_sicphone_usercontrol_wmlcard_ascx'没有名为'Literal'的公共属性。
添加RuntimeFilledLiteral.Text
后:
'sic:Card'的'InnerText'属性不允许子对象。
与上述相同,但将WmlCard的属性<PersistenceMode(PersistenceMode.InnerDefaultProperty), ParseChildren(True, "InnerText")>
类型从InnerText
更改为String
:
“System.Collections.IList”中不允许使用文字内容(“任何文字。”)。
添加List(Of Object)
并覆盖<ParseChildren(False)>
后:
没有错误消息,但在我有机会更改其内部控件运行时属性之前,WmlCard的内容将呈现为html。
如果我更改WmlCard以继承AddParsedSubObject
而不是System.Web.UI.WebControls.PlaceHolder
:
这里不允许使用'... UserControl.WmlCard',因为它没有扩展类'System.Web.UI.UserControl'。
答案 0 :(得分:3)
找到一种有效的方式:
1)没有任何东西放在我的控制之内(WmlCard.ascx)。
2)将属性<ParseChildren(False)>
添加到WmlCard。
3)在WmlCard上为事件PreRender添加了一个处理程序:
Private Sub Page_PreRender(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.PreRender
Dim litBefore As New Literal()
litBefore.Text = String.Format("<card id=""{0}"" title=""{1}""><p>", Me.CardId, Me.Title)
Dim litAfter As New Literal()
litAfter.Text = "</p></card>"
Me.Controls.AddAt(0, litBefore)
Me.Controls.Add(litAfter)
End Sub
就是这样。一切正常。感谢你的帮助,想通过这个!
答案 1 :(得分:0)
您需要的是模板化用户控件。
请查看本文以获取详细的操作方法:http://msdn.microsoft.com/en-us/library/36574bf6.aspx。
答案 2 :(得分:0)
实际上你可以创建一个自定义用户控件,从占位符继承,你的问题应该解决吗?
你可以按照建议采用模板控制方式,但我没有看到你想要这样做的原因。
[SupportsEventValidation, DefaultEvent("YourEventName")]
[ParseChildren(true)]
[PersistChildren(false)]
[ToolboxBitmap(typeof(System.Web.UI.WebControls.Panel))]
public class MyCustomControl : System.Web.UI.WebControls.PlaceHolder, INamingContainer, IPostBackDataHandler, IPostBackEventHandler
您可以覆盖Render方法来控制呈现的HTML。我很难看到你的实际问题。
答案 3 :(得分:0)
使这项工作足够简单。
[ParseChildren(false)]
public class CssControl : System.Web.UI.UserControl
{
protected override void Render(HtmlTextWriter writer)
{
string html = null;
using(var innerWriter = new System.IO.StringWriter())
using(var htmlWriter = new HtmlTextWriter(innerWriter))
{
base.Render(htmlWriter);
html = innerWriter.GetStringBuilder().ToString();
}
var min = ScriptAndCssParser.MinifyCssFromHtml(html);
writer.Write(min);
}
}
在我的情况下,我的目标是允许母版级控件具有子HTML和服务器控件,例如asp:content
块。这样,Viewpages可以将样式表向上传递到母版页。
然后,我想拦截所有生成的HTML,并缩小CSS文件。缩小部分超出了此问题的范围,但是上述ParseChildren(false)
防止了.aspx中的“元素不能包含...”错误,然后在内部编写器上调用base.Render()
可以您可以使用现有的Web Forms管道为您完成服务器控件和纯HTML内容的所有呈现。