【问题标题】:UserControl with templates, change server-control rendered ID带有模板的用户控件,更改服务器控件呈现的 ID
【发布时间】:2017-12-09 14:30:27
【问题描述】:

TL;DR...

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


在我的 ASP.NET Web 应用程序中,我创建了一个带有多个一次性模板的 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 是标记中的&lt;asp:PlaceHolder&gt;)

这是在页面中使用的控件示例(由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>

当&lt;asp:Button&gt;被渲染到HTML时,元素的id会导致...

id="ctl00_content_muc1_ctl00_btnMyButton"

...其中第二个ctl00 是MyUserCtrlLiteralContainer 实例的ID。


有没有办法让控件的id呈现如下? (所以不使用容器的ID)

ctl00_content_muc1_btnMyButton

或者更好的是,有没有办法让控件的id呈现如下? (所以既不使用用户控件的ID,也不使用容器的ID)

ctl00_content_btnMyButton

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

【问题讨论】:

  • 您需要 MyUserCtrlLiteralContainer 吗? (也就是说,您可以直接在占位符内实例化模板吗?)如果您确实需要 MyUserCtrlLiteralContainer,是否需要实现 INamingContainer?
  • @MichaelLiu - 再次感谢您的意见。您的假设是正确的,即不需要额外的MyUserCtrlLiteralContainer,而是可以使用TemplateContainer(GetType(INamingContainer)) 设置属性并直接实例化到占位符中......这导致ctl00_content_muc1_btnMyButton 这是向前迈出的一大步.我觉得到达ctl00_content_btnMyButton 可能有点太远了,但如果你有任何想法,那就开火吧。同时,我建议您根据您的建议创建一个答案,这样我就可以给您应得的信任
  • @MichaelLiu - 啊,需要注意的一件事是,如果您(完全有机会)在 UserControl 实例中有一个与 UserControl 标记中的 &lt;asp:PlaceHolder&gt; 同名的控件,它会抱怨重复的 ID - 这是公平的

标签: c# asp.net vb.net user-controls


【解决方案1】:

我不相信您能够让 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

【讨论】:

  • 谢谢 - 我已经知道ClientIDMode,但正如你已经说过的,它不包括父结构
  • 你可以手动伪造它,虽然这听起来一点也不好玩
【解决方案2】:

按钮id 包括muc1 和ctl00,因为UserControl 和MyUserCtrlLiteralContainer 实现了INamingContainer。如果您不希望 id 包含这些部分,但您确实希望 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 设为未设置。

【讨论】:

  • 再一次,你是我的个人英雄 - 谢谢@Michael - 这正好解决了问题。我本来希望能够快速轻松地控制 HTML(通过实际标记而不是代码),但这正是我需要的......再次感谢你 :-)
  • @freefaller:如果你有很多静态 HTML,你可以调用writer.Write("&lt;big chunk of HTML&gt;"),而不是 AddAttribute 和 RenderBeginTag。
  • 不错的想法 - 是的,这也很有效 - 再次感谢您:-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-18
  • 2010-10-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-12
相关资源
最近更新 更多