具有内部控件的Asp.net用户控件

时间:2011-03-03 16:36:32

标签: asp.net web-user-controls

我需要开发一个类似模板的用户控件,它可以接受任意内容,包括其他控件。

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'。

4 个答案:

答案 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内容的所有呈现。