ASP.NET动态用户控件

3
我相信这个问题已经被问了无数次,但我还没有找到解决我的问题的答案。
我正在以编程方式向一个简单的aspx页面上的PlaceHolder添加一些自定义用户控件。所有用户控件的Postback都能正常工作,除了其中一个带有GridView的控件。
由于某种原因,从此控件内部触发的任何postback,在第一次点击时不会调用指定的事件,但是在之后的所有点击中都能正常工作。我不知道为什么会出现这种情况,但我找到的许多解决方案都建议给ascx用户控件添加一个ID,但在我的情况下这并不起作用。
我查看了在第一次点击之前和之后生成的页面的源文件,用于调用postback的javascript发生了变化,即:
第一次点击之前:onclick="javascript:__doPostBack('tmpControlID$sgvPrimaryEmploymentHistory','Select$0')"
第一次点击之后:onclick="javascript:__doPostBack('OFFHome1$tmpControlID$sgvPrimaryEmploymentHistory','Select$0')"
OFFHome1是存在于aspx页面上的父用户控件。所有其他控件都添加到该控件中的占位符中。
<%@ Control Language="vb" AutoEventWireup="false" CodeBehind="OFFHome.ascx.vb" Inherits="UmbracoUserControls.OFFHome" %>
<asp:PlaceHolder ID="phOFFSection" runat="server"></asp:PlaceHolder>

内容不太复杂。然后在代码后台,使用以下方法将控件加载到占位符中:

Private Sub LoadNextOFFStep()
    Dim ControlName As String = "TestControl.ascx"
    phOFFSection.Controls.Clear()
    If ControlName IsNot Nothing AndAlso ControlName <> String.Empty Then
        Dim NewControl As Object = LoadControl(ControlName)

        With NewControl
            .ID = USERCONTROLNAME
            Dim StepCompleted As Boolean = .FillControl()
            If StepCompleted Then
                Exit Sub
            End If
            Dim AllowSkip As Boolean = .AllowSkip()
            btnSkip.Visible = AllowSkip
        End With
        phOFFSection.Controls.Add(NewControl)
    End If
End Sub

这并不是什么太复杂的问题。USERCONTROLNAME只是一个常量,其值为"tmpControlID"。

导致我困扰的控件有点复杂,我最初使用的是我们创建的自定义GridView控件,但已将其替换为标准的asp控件以查看问题是否仍然存在,结果仍然存在。

任何触发postback的控件上的按钮都会在第一次失败,而所有后续点击都将正常工作。在第一次点击时,只会调用Page_Load事件。

我做错了什么?


在页面生命周期的哪个阶段调用 LoadNextOFFStep() 函数? - o.k.w
它在OFFHome.ascx控件的Page_Load中被调用。 即: Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load If Not IsPostBack Then LoadNextOFFStep() Else LoadCurrentOFFStep(False) End If End SubLoadCurrentOFFStep执行类似的任务,但仅用于在postback后重新添加控件。 - Chris
@Chirs:我已经删除了我的回答,以防你想知道它去哪了。我认为那不会起作用。 - o.k.w
我有一个类似的函数,用于在回发时重新填充控件。LoadNextOFFStep()函数稍微复杂一些,因为它实际上会访问数据库来检查它应该加载哪个控件,因为它被用在向导中。 - Chris
如果回发重新创建了不同的子控件或嵌套控件集,那么这可能解释了为什么问题只在第一次回发时触发。这是我关注的重点。 - o.k.w
显示剩余2条评论
2个回答

1

在花费了太多时间之后,我终于解决了这个问题。

问题出在事件的顺序上,但并不是我原先想象的那样。FillControl函数被调用时,用户控件还没有添加到占位符中。我将其更改为在用户控件添加到占位符后再调用FillControl函数,现在它可以一次性正常工作了。

基本上,代码现在看起来像这样:

Private Sub LoadNextOFFStep()
    Dim ControlName As String = "TestControl.ascx"
    phOFFSection.Controls.Clear()
    If ControlName IsNot Nothing AndAlso ControlName <> String.Empty Then
        Dim NewControl As Object = LoadControl(ControlName)

        With NewControl
            .ID = USERCONTROLNAME
            Dim AllowSkip As Boolean = .AllowSkip()
            btnSkip.Visible = AllowSkip
        End With
        phOFFSection.Controls.Add(NewControl)
        Dim StepCompleted As Boolean = CType(phOFFSection.Controls(0), Object).FillControl()
        If StepCompleted Then
            LoadNextOFFStep()
            Exit Sub
        End If
    End If
End Sub

感谢大家的帮助。


0

嗯……第一个问题的答案很简单:首次失败是因为控件的 ID(或者更准确地说,回发脚本中的 ID)在后续页面加载时不同。在随后的点击中它可以工作是因为控件的 ID 保持不变。

现在关于这是为什么……就比较困难了!但可能与操作顺序有关。

尝试明确设置 NewControl 的 NamingContainer 值:

    With NewControl
        .NamingContainer = OffHomeOne; // whatever
        .ID = USERCONTROLNAME

事实证明,我无法显式设置NamingContainer,因为它是只读属性。 - Chris
哦。你是对的。好吧...这绝对与你的问题有关。出于好奇,你能在Init中调用这个方法而不是Page_Load吗?有任何功能上的区别吗? - Bryan
似乎没有任何区别。我尝试使用DataGrid而不是GridView,在第一次点击时,网格实际上会消失。在以后的点击中它会正常工作... - Chris

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接