asp.net - 动态更新面板和用户控件问题

标签 asp.net user-controls webforms updatepanel .net-4.5

在将项目从 3.5 迁移到 4.5 时,在 ASP.Net WebForms 中遇到了一个有趣的问题。

有问题的站点非常动态 - 该页面是基于 CMS 方式的配置构建的。

然而,在 4.5 中,我们遇到了一个问题——当通过单击按钮将更多内容添加到页面中时,并非所有内容的标记都会出现。 (在测试时,问题也在 .net 4.0 中重现)。

此处演示的是一个非常精简的示例,该示例仅使用默认的 WebForms 项目模板(在本例中为 VB)。

在 Default.aspx 中添加以下标记:

<asp:UpdatePanel ID="udpTrigger" runat="server" UpdateMode="Always">
    <ContentTemplate>
        <asp:button id="btnGo" runat="server" Text ="Go" />
    </ContentTemplate>
</asp:UpdatePanel>
<asp:Panel ID="pnlContainer" runat="server">
</asp:Panel>

在 Default.aspx.vb 中添加以下代码:
Dim _udp As UpdatePanel

Private Sub Page_Init(sender As Object, e As EventArgs) Handles Me.Init    
    _udp = New UpdatePanel()
    _udp.ID = "udpTarget"
    _udp.UpdateMode = UpdatePanelUpdateMode.Conditional

    pnlContainer.Controls.Add(_udp)        
End Sub

Private Sub btnGo_Click(sender As Object, e As EventArgs) Handles btnGo.Click    
    Dim ctrl = LoadControl("Control.ascx")        

    Dim pnlWrapper = New Panel With {.ID = "pnlWrapper"}
    pnlWrapper.Controls.Add(ctrl)

    _udp.ContentTemplateContainer.Controls.Add(pnlWrapper)        
    _udp.Update()            
End Sub

注:在用户控件和更新面板之间有一个环绕面板。这用于演示输出中缺少哪些标记。

创建一个 Control.ascx并添加以下内容:
<asp:Panel ID="pnlControl" runat="server"></asp:Panel>

一旦我们点击 btnGo控件,包装面板和 control.ascx 应添加到页面中。

在 .Net 3.5 中,这正是发生的事情:
<div id="pnlContainer">                    
    <div id="udpTarget">
        <div id="pnlWrapper">
            <div id="ctl05_pnlControl">
            </div>
        </div>
    </div>
</div>

在 .Net 4.5 中,包装面板不会出现 - 只是用户控件:
<div id="MainContent_pnlContainer">          
    <div id="MainContent_udpTarget">
       <div id="MainContent_ctl02_pnlControl">
       </div>
    </div>
</div>

如果更新面板位于网页的标记中,则不会出现此问题,但在这种情况下这是不可能的。

切换使用哪个 LoadControl 重载(到 LoadControl(type,params) 生成包装面板,但没有标记 - 这似乎是一个单独的问题)。

检查 fiddler2 中的响应正文显示服务器端省略了包装器面板(即我们不会在客户端 ajax 处理中丢失它)

那么是否有任何解决方法,或者甚至是针对此行为的某种修复补丁 - 考虑到 .Net 4 在 3.5 中很好,它似乎确实存在问题。

现在也把这个贴在我的 blog here 上收集我为获得修复或解决方法所做的任何尝试。

更新

根据@jadarnel27 的指示,以下步骤没有在 VS2010 上重现问题,我已经在几台不工作的机器上尝试了这些步骤。
  • 首先关闭另一台 VS2013 机器:确实重现了这个问题。
  • 接下来,我的旧开发机器,运行 VS2012 Express For Web:没有重现问题

  • 所以在这个阶段看起来问题仅限于VS2013。接下来在VS2013中尝试一些不同的设置。

    现在已将此发布到 Microsoft Connect here .

    最佳答案

    解决方法

    我现在有一个解决方法。我正在使用 UserControlLoader服务器控件包装用户控件,并通过覆盖 RenderContents 单独呈现它
    UserControlLoader 的代码是:

    ''' <summary>
    ''' UserControl Loader - loads a user control
    ''' Works around a problem with ASP.Net Webforms in 4.0/4.5
    ''' </summary>
    <ToolboxData("<{0}:UserControlLoader runat=server></{0}:UserControlLoader>")> _
    Public Class UserControlLoader
        Inherits WebControl
    
        Public ReadOnly Property Control As Control
            Get
                Return _control
            End Get
        End Property
        Private _control As Control
    
        Public Sub LoadControl(page As Page, virtualPath As String)
            _control = page.LoadControl(virtualPath)
            Me.Controls.Add(_control)
        End Sub
    
        Public Overrides Sub RenderBeginTag(writer As HtmlTextWriter)
            'Don't render anything
        End Sub
    
        Public Overrides Sub RenderEndTag(writer As HtmlTextWriter)
            'Don't render anything
        End Sub
    
        ''' <summary>
        ''' Overrides RenderContent to write the content to a separate writer,
        ''' then adds the rendered markup into the main HtmlTextWriter instance.
        ''' </summary>
        Protected Overrides Sub RenderContents(ByVal writer As HtmlTextWriter)
    
            If _control Is Nothing Then Return
    
            Using sw = New StringWriter()
                Using hw = New HtmlTextWriter(sw)
    
                    MyBase.RenderContents(hw)
    
                    writer.Write(sw.ToString)
    
                End Using
            End Using
    
        End Sub
    
    End Class
    

    用法:

    要将其实现到列出的娱乐步骤中,btnGo事件处理程序变为:
    Private Sub btnGo_Click(sender As Object, e As EventArgs) Handles btnGo.Click
    
        Dim loader = new UserControlLoader()
        loader.LoadControl(Page,"Control.ascx")     
    
        Dim pnlWrapper = New Panel With {.ID = "pnlWrapper"}
        pnlWrapper.Controls.Add(loader)
    
        _udp.ContentTemplateContainer.Controls.Add(pnlWrapper)        
        _udp.Update() 
    
    End Sub
    

    关于asp.net - 动态更新面板和用户控件问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20473261/

    相关文章:

    c# - 页脚按钮的 Gridview colspan

    javascript - 在 Controller 上找不到公共(public)操作方法

    asp.net - 如何使用 ASP.NET MVC 4 实现基于角色的用户管理系统

    c# - ID为 'UpdatePanel1'的UpdatePanel的Controls属性不能直接修改

    .net - WinForms 中的 Control 与 UserControl?

    c# - 部分用户控制

    mysql - 将Web表单数据提交到MySQL数据库表时如何获取登录Azure B2C用户的id?

    ruby-on-rails - rails : Best practice to store user settings?

    webforms - 如何在 ASP .Net 中开发将遵循工作流中定义的过程的 Web 应用程序?