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



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

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

问题场景如下:

1)单击第二个按钮(Add Approver按钮)两次,并在两个生成的文本框中输入一些值(为了便于分析,使值不同)。

2)点击第一个按钮(添加文档按钮)一次。(这里不需要在生成的文本框中添加任何值)

在这一点上一切似乎都是正确的。查看页面源代码,我看到两个"Approver"文本框的ID为ctl02_txtApprover和ctl03_txtApprover,一个"Document"文本框的ID为ctl04_txtDocument。

  1. 再次点击第一个按钮(添加文档按钮)。

此时,第一个"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>

Default.aspx.vb

Public Class _Default
Inherits System.Web.UI.Page
Private Const VIEWSTATE_DOCUMENT_COUNT As String = "DocumentCount"
Private Const VIEWSTATE_APPROVER_COUNT As String = "ApproverCount"
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    If Not IsPostBack Then
        ViewState(VIEWSTATE_DOCUMENT_COUNT) = 0
        ViewState(VIEWSTATE_APPROVER_COUNT) = 0
    Else
        're-display any preexisting dynamic sections on postback
        AddAllDocumentInfoSections()
        AddAllApproverSections()
    End If
End Sub
Protected Sub btnAddDocument_Click(sender As Object, e As EventArgs) Handles btnAddDocument.Click
    ViewState(VIEWSTATE_DOCUMENT_COUNT) += 1
    AddDocumentSection()
End Sub
Protected Sub btnAddApprover_Click(sender As Object, e As EventArgs) Handles btnAddApprover.Click
    ViewState(VIEWSTATE_APPROVER_COUNT) += 1
    AddApproverSection()
End Sub
Private Sub AddAllDocumentInfoSections()
    For i As Integer = 0 To ViewState(VIEWSTATE_DOCUMENT_COUNT) - 1
        AddDocumentSection()
    Next
End Sub
Private Sub AddAllApproverSections()
    For i As Integer = 0 To ViewState(VIEWSTATE_APPROVER_COUNT) - 1
        AddApproverSection()
    Next
End Sub
Private Sub AddDocumentSection()
    Dim c As UserControl = LoadControl("~/Document.ascx")
    phDocument.Controls.Add(c)
End Sub
Private Sub AddApproverSection()
    Dim c As UserControl = LoadControl("~/Approver.ascx")
    phApprover.Controls.Add(c)
End Sub
End Class

Document.ascx

<%@ Control Language="vb" AutoEventWireup="false" CodeBehind="Document.ascx.vb" Inherits="WebApplicationUserControlTest.Document" %><asp:TextBox ID="txtDocument" runat="server" /><br /><br />

Approver.ascx

<%@ Control Language="vb" AutoEventWireup="false" CodeBehind="Approver.ascx.vb" Inherits="WebApplicationUserControlTest.Approver" %><asp:TextBox ID="txtApprover" runat="server" /><br /><br />

我使用的是Visual Studio 2010。目标框架是4.0。我试过改变clientIDMode,但这似乎没有什么不同。我遇到了一个错误与。net或有什么问题与我的代码?

你的代码有问题。

如果您动态地将控件添加到控件树中的相同命名容器中,那么您需要在每次回发后以相同的顺序添加它们。

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

在步骤2中,您按以下顺序添加了三个控件:
  • 审批人1 (AddAllApproverSections)
  • 审批人2 (AddAllApproverSections)
  • DocumentInfo 1 (btnAddDocument_Click)

但是在回发之后,按照以下顺序重新生成它们:

  • DocumentInfo 1 (AddAllDocumentInfoSections)
  • 审批人1 (AddAllApproverSections)
  • 审批人2 (AddAllApproverSections)

因此控件id不相同,您看到的问题。

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

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

这里的问题是您在初始化控件集合和ViewState之后修改它们。永远不要在Page Load事件中动态添加控件。

您需要在Page生命周期的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

我相信你可能不得不改变你为这些控件存储"计数"的方式,因为viewstate信息在这个阶段还不可用。在这种情况下,我将把它存储为Session变量。您只需要在整个代码示例中用"Session"更改对"ViewState"的引用,如下所示:

Private Sub AddAllDocumentInfoSections()
    For i As Integer = 0 To Session(VIEWSTATE_DOCUMENT_COUNT) - 1
        AddDocumentSection()
    Next
End Sub

相关内容

  • 没有找到相关文章

最新更新