带模板的 UserControl,更改服务器控件呈现的 ID

UserControl with templates, change server-control rendered ID

TL;DR...

使用一次性模板创建 [UserControl] 时,是否可以将服务器端控件放置在这些模板中以呈现其 id 而无需 UserControl 或容器 ID?


在我的 ASP.NET 网络应用程序中,我创建了一个带有多个一次性模板的 UserControl(我在这里只给出了其中一个模板的代码)...

Public Class MyUserCtrl
    Inherits System.Web.UI.UserControl

    Private Class MyUserCtrlLiteralContainer
        Inherits Control
        Implements INamingContainer
    End Class

    <TemplateContainer(GetType(MyUserCtrlLiteralContainer)),
     TemplateInstance(TemplateInstance.Single),
     PersistenceMode(PersistenceMode.InnerProperty)>
    Public Property FirstTemplate As ITemplate

    Private Sub Page_Init(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Init
        If FirstTemplate IsNot Nothing Then
            Dim container As New MyUserCtrlLiteralContainer()
            FirstTemplate.InstantiateIn(container)
            plhFirst.Controls.Add(container)
        End If
    End Sub
End Class    

(注意,plhFirst 是标记中的 <asp:PlaceHolder>

这是页面中使用的控件示例(由 Master 页面控制)...

<asp:Content runat="server" ID="content" ContentPlaceHolderID="mainContent">
  <uc1:MyUserCtrl runat="server" id="muc1">
    <FirstTemplate>
      <asp:Button runat="server" id="btnMyButton" />
    </FirstTemplate>
  </uc1:MyUserCtrl>
</asp:Content>

<asp:Button> 呈现给 HTML 时,元素的 id 会导致...

id="ctl00_content_muc1_ctl00_btnMyButton"

...其中第二个 ctl00MyUserCtrlLiteralContainer 实例的 ID。


有没有办法让控件的id渲染成下面这样? (所以没有使用容器的ID)

ctl00_content_muc1_btnMyButton

或者更好的是,有什么办法可以让控件的id渲染成下面这样吗? (所以用户控件和容器的ID都没有被使用)

ctl00_content_btnMyButton

或者,是否有不同的方法来实例化 UserControl 中的控件,这会导致上述任一情况?

我不相信您能够让 ID 看起来像您希望的那样,因为它们被设计为显示控制层次结构,尽管它们很丑陋。

可以,但是如果您愿意,可以在控件、页面或整个项目上使用静态 ID。回顾 2010 年这篇方便的 ScottGu 文章:

https://weblogs.asp.net/scottgu/cleaner-html-markup-with-asp-net-4-web-forms-client-ids-vs-2010-and-net-4-0-series

您要查找的部分是 Today’s Cleaner Markup Topic: Client IDs

按钮 id 包括 muc1ctl00,因为 UserControl 和 MyUserCtrlLiteralContainer 实现了 INamingContainer。如果您不希望 id 包含这些部分,但您 do 希望 id 包含其他祖先 ID,那么您不能使用那些控件类型。

移除 ctl00: 除非你特别需要自定义容器控件,否则你可以删除 MyUserCtrlLiteralContainer 并直接在 PlaceHolder 中实例化模板。

删除 muc1: 您必须将 UserControl 重写为未实现 INamingContainer 的服务器控件。

这是一个示例实现:

<ParseChildren(True)>
Public Class MyUserCtrl
    Inherits Control

    Private plhFirst As PlaceHolder

    <TemplateInstance(TemplateInstance.Single),
     PersistenceMode(PersistenceMode.InnerProperty)>
    Public Property FirstTemplate As ITemplate

    Private Sub Page_Init(sender As Object, e As EventArgs) Handles MyBase.Init
        plhFirst = New PlaceHolder()
        Controls.Add(plhFirst)

        If FirstTemplate IsNot Nothing Then
            FirstTemplate.InstantiateIn(plhFirst)
        End If
    End Sub

    Protected Overrides Sub Render(writer As HtmlTextWriter)
        ' <div class="myUserCtrl">
        writer.AddAttribute(HtmlTextWriterAttribute.Class, "myUserCtrl")
        writer.RenderBeginTag(HtmlTextWriterTag.Div)

        ' <div class="firstControls">
        writer.AddAttribute(HtmlTextWriterAttribute.Class, "firstControls")
        writer.RenderBeginTag(HtmlTextWriterTag.Div)

        plhFirst.RenderControl(writer)

        ' </div>
        writer.RenderEndTag()

        ' </div>
        writer.RenderEndTag()
    End Sub
End Class

注意: 为避免可能的 ID 冲突,我特意未设置 plhFirst.ID