ASP.NET-两个用户控件-在运行时添加多个实例

ASP.NET-两个用户控件-在运行时添加多个实例,asp.net,vb.net,Asp.net,Vb.net,我有一个VB ASP.NET web应用程序,有两个用户控件,每个控件包含一个文本输入。有两个提交按钮,每个按钮对应一个用户控件 单击按钮可添加其相应用户控件的实例。在大多数情况下,除了在特定的场景中,文本框的ID被混淆,从而混淆了以前输入的值之外,这一点是有效的 问题场景如下所示: 1) 单击第二个按钮(添加审批人按钮)两次,并在两个结果文本框中输入一些值(为了便于分析,请使值不同) 2) 单击第一个按钮(添加文档按钮)一次。(无需在此处生成的文本框中添加任何值。) 在这一点上,一切似乎都是正

我有一个VB ASP.NET web应用程序,有两个用户控件,每个控件包含一个文本输入。有两个提交按钮,每个按钮对应一个用户控件

单击按钮可添加其相应用户控件的实例。在大多数情况下,除了在特定的场景中,文本框的ID被混淆,从而混淆了以前输入的值之外,这一点是有效的

问题场景如下所示:

1) 单击第二个按钮(添加审批人按钮)两次,并在两个结果文本框中输入一些值(为了便于分析,请使值不同)

2) 单击第一个按钮(添加文档按钮)一次。(无需在此处生成的文本框中添加任何值。)

在这一点上,一切似乎都是正确的。查看页面源代码,我看到两个“Approver”文本框的ID为ctl02\u txtApprover和ctl03\u txtApprover,一个“Document”文本框的ID为ctl04\u txtDocument

  • 再次单击第一个按钮(添加文档按钮)
  • 此时,第一个“Approver”文本框中的值消失。第二个“Approver”文本框中的值将迁移到第一个“Approver”文本框。查看页面源,两个“Approver”文本框的ID已更改为ctl03_txtApprover和ctl04_txtApprover。考虑到文本框ID已更改,迁移的值是有意义的。换句话说,ViewState看起来正确,但控件ID不正确

    我已经尽可能地简化了代码,并将其发布在这里

    Default.aspx

    <%@ Page Language="vb" AutoEventWireup="false" CodeBehind="Default.aspx.vb" Inherits="WebApplicationUserControlTest._Default" %>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
            <asp:PlaceHolder ID="phDocument" runat="server" />
            <asp:Button ID="btnAddDocument" runat="server" Text="Add Document" />
            <br /><br />
            <asp:PlaceHolder ID="phApprover" runat="server" />
            <asp:Button ID="btnAddApprover" runat="server" Text="Add Approver" />
        </form>
    </body>
    </html>
    
    <%@ Control Language="vb" AutoEventWireup="false" CodeBehind="Document.ascx.vb" Inherits="WebApplicationUserControlTest.Document" %><asp:TextBox ID="txtDocument" runat="server" /><br /><br />
    
    <%@ Control Language="vb" AutoEventWireup="false" CodeBehind="Approver.ascx.vb" Inherits="WebApplicationUserControlTest.Approver" %><asp:TextBox ID="txtApprover" runat="server" /><br /><br />
    
    Document.ascx

    <%@ Page Language="vb" AutoEventWireup="false" CodeBehind="Default.aspx.vb" Inherits="WebApplicationUserControlTest._Default" %>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
            <asp:PlaceHolder ID="phDocument" runat="server" />
            <asp:Button ID="btnAddDocument" runat="server" Text="Add Document" />
            <br /><br />
            <asp:PlaceHolder ID="phApprover" runat="server" />
            <asp:Button ID="btnAddApprover" runat="server" Text="Add Approver" />
        </form>
    </body>
    </html>
    
    <%@ Control Language="vb" AutoEventWireup="false" CodeBehind="Document.ascx.vb" Inherits="WebApplicationUserControlTest.Document" %><asp:TextBox ID="txtDocument" runat="server" /><br /><br />
    
    <%@ Control Language="vb" AutoEventWireup="false" CodeBehind="Approver.ascx.vb" Inherits="WebApplicationUserControlTest.Approver" %><asp:TextBox ID="txtApprover" runat="server" /><br /><br />
    


    审批人.ascx

    <%@ Page Language="vb" AutoEventWireup="false" CodeBehind="Default.aspx.vb" Inherits="WebApplicationUserControlTest._Default" %>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
            <asp:PlaceHolder ID="phDocument" runat="server" />
            <asp:Button ID="btnAddDocument" runat="server" Text="Add Document" />
            <br /><br />
            <asp:PlaceHolder ID="phApprover" runat="server" />
            <asp:Button ID="btnAddApprover" runat="server" Text="Add Approver" />
        </form>
    </body>
    </html>
    
    <%@ Control Language="vb" AutoEventWireup="false" CodeBehind="Document.ascx.vb" Inherits="WebApplicationUserControlTest.Document" %><asp:TextBox ID="txtDocument" runat="server" /><br /><br />
    
    <%@ Control Language="vb" AutoEventWireup="false" CodeBehind="Approver.ascx.vb" Inherits="WebApplicationUserControlTest.Approver" %><asp:TextBox ID="txtApprover" runat="server" /><br /><br />
    



    我正在使用VisualStudio2010。目标框架是4.0。我尝试过更改ClientMode,但这似乎没有什么不同。我是否在.NET中遇到错误,或者我的代码有什么问题?

    这里的问题是,在初始化控件集合和视图状态后,您正在修改它们永远不要在页面加载事件中动态添加控件。

    您需要在的Page_Init阶段添加控件,并从Page_Load事件中的else语句中删除代码。您的新Page_Init事件如下所示:

    Protected Sub Page_Init(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Init
        AddAllDocumentInfoSections()
        AddAllApproverSections()
    End Sub
    
    Private Sub AddAllDocumentInfoSections()
        For i As Integer = 0 To Session(VIEWSTATE_DOCUMENT_COUNT) - 1
            AddDocumentSection()
        Next
    End Sub
    
    我认为您可能必须更改存储这些控件的“计数”的方式,因为视图状态信息在此阶段尚不可用。在这种情况下,我只将其存储为会话变量。您只需在整个代码示例中使用“会话”更改对“ViewState”的引用,如下所示:

    Protected Sub Page_Init(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Init
        AddAllDocumentInfoSections()
        AddAllApproverSections()
    End Sub
    
    Private Sub AddAllDocumentInfoSections()
        For i As Integer = 0 To Session(VIEWSTATE_DOCUMENT_COUNT) - 1
            AddDocumentSection()
        Next
    End Sub
    

    您的代码有问题

    如果将控件动态添加到控件树中的同一命名容器中,则需要在每次回发后按相同顺序添加它们

    在你的情况下,你没有这样做

    在步骤2中,您已按此顺序添加了三个控件:

    • 批准人1(添加所有批准)
    • 批准人2(添加所有批准)
    • 文档信息1(btnAddDocument\u单击)
    但在回发之后,您将按照以下顺序重新生成它们:

    • DocumentInfo 1(添加所有DocumentInfoSections)
    • 批准人1(添加所有批准)
    • 批准人2(添加所有批准)
    因此,控件ID不同,并且您看到的问题也不同

    一种解决方案可能是在ViewState中存储表示控件添加顺序的其他信息,以便可以按相同顺序重新创建它们


    但我可能倾向于采用另一种方法,例如,将DocumentInfo部分放在重复器的模板中,将Approver部分放在第二个重复器中。每个中继器都将数据绑定到一个合适的集合,添加一个项目(Approver或DocumentInfo)可以通过向相关集合添加一个元素并调用DataBind来实现。

    谢谢。我以前尝试过使用页面初始化。此外,虽然您提供的代码不会对任何内容产生负面影响,但结果功能与以前完全相同。“您不应在页面加载事件中动态添加控件。”-我将对此进行限定:您可以在页面加载中动态添加控件,以后只要您知道自己在做什么。@Joe,这是一个有效的点=)我对您的答案投了赞成票,因为您发现了我在整个问题上遗漏的内容。回答得好。仅供参考,只要我使用两个不同的命名容器,我就可以继续使用Page_Load事件和ViewState。可能是.Net的最新版本发生了一些变化,使得以前对Page_Init的限制不再相关了?再次谢谢你,乔。使用两个中继器,每个用户控件使用一个中继器似乎有效。查看页面源,每个文本框的名称都以其转发器的名称作为前缀,这很有意义。我以前曾尝试使用两个面板来实现同样的想法,但都没有效果。我想我需要更好地理解命名容器。@Cienfuegos,面板不是命名容器(没有实现InAdminContainer标记接口),所以这就是你的尝试失败的原因。在这种情况下,我认为中继器是一种更好的方法。