动态创建的用户控件无法处理 PostBack 上的事件

Posted

技术标签:

【中文标题】动态创建的用户控件无法处理 PostBack 上的事件【英文标题】:User Control created dynamically not able to handle events on PostBack 【发布时间】:2010-09-10 16:54:07 【问题描述】:

我有一个用户控件,它使用页面初始化中的以下代码动态加载到页面中。

Dim oCtl As Object
oCtl = LoadControl("~/Controls/UserControl1.ascx")

oCtl.Id = "UserControl11"
PlaceHolder1.Controls.Clear()
PlaceHolder1.Controls.Add(oCtl)

用户控件还包含一个按钮,我无法捕获用户控件中的按钮单击。

【问题讨论】:

【参考方案1】:

您正在做的一些事情既不需要,也可能会导致您的问题。

这些是:

    无需在会话中存储控制对象。控件本身应根据需要使用 ViewState 和 Session State 来存储信息,而不是整个实例。 创建控件时不应检查 PostBack。每次都必须创建它以允许 ViewState 工作和连接事件。 在加载 ViewState 后加载的控件通常无法正常运行,因此请尽可能避免在 Page Load 事件期间加载。

此代码适用于我:


默认.aspx

<%@ Page Language="vb" AutoEventWireup="false" CodeBehind="Default.aspx.vb" Inherits="Test_User_Control._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="PlaceHolder1" runat="server" />
    </form>
</body>
</html>

默认.aspx.vb

Partial Public Class _Default
    Inherits System.Web.UI.Page

    Private Sub Page_Init(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Init

        Dim control As Control = LoadControl("~/UserControl1.ascx")
        PlaceHolder1.Controls.Add(control)

    End Sub
End Class

UserControl1.ascx

<%@ Control Language="vb" AutoEventWireup="false" CodeBehind="UserControl1.ascx.vb" Inherits="Test_User_Control.UserControl1" %>
<asp:Label ID="Label1" Text="Before Button Press" runat="server" />
<asp:Button ID="Button1" Text="Push me" runat="server" />

UserControl1.ascx.vb

Public Partial Class UserControl1
    Inherits System.Web.UI.UserControl

    Private Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click
        Label1.Text = "The button has been pressed!"
    End Sub

End Class

【讨论】:

【参考方案2】:

在 .NET 进入页面生命周期的“回发事件处理”步骤之前,您必须确保该控件存在于页面上。由于控件是动态添加的,因此您必须确保在每次回发时重新创建该控件,以便它可以找到触发事件的控件。

【讨论】:

【参考方案3】:

确保在每次回发时加载控件 - 如果回发页面时控件不在控件树中,ASP.NET 将不会引发按钮单击事件。

【讨论】:

【参考方案4】:

我刚刚遇到了与您类似的问题,只是在我的情况下我没有使用会话来存储控件。

就我而言,我在这一行中找到了问题:

PlaceHolder1.Controls.Clear()

我所做的是创建一个子控件并将它们添加到 Page_Init 上的父容器中,然后处理一些事件处理程序,然后在 Page_PreRender 上我使用更新的数据再次重新创建整个列表。

我在这种情况下使用的解决方案是在页面周期的早期阶段创建一次控件集合。

【讨论】:

【参考方案5】:

几个问题:

    在页面生命周期的哪个时间点加载控件? 事件处理程序代码在哪里?在控件本身中还是您尝试将其连接到页面? 到目前为止,您为此次活动做了哪些工作?

最后,.Net 的样式指南特别建议反对使用任何像 oCtl 中的 o 这样的匈牙利前缀疣,并且您应该将其键入为控件而不是对象。

【讨论】:

接受匈牙利语前缀的点,以后要记住这一点。我将在下面的评论中粘贴完整的代码。非常感谢您的反馈【参考方案6】:

这是页面的完整代码

Partial Class DynamicLoad
    Inherits System.Web.UI.Page

    Protected Sub Page_Init(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Init
        If IsPostBack Then
            If Not (Session("ctl") Is Nothing) Then
                Dim oCtl As Object
                oCtl = Session("ctl")
                PlaceHolder1.Controls.Add(oCtl)
            End If
        End If
    End Sub


    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        If Not IsPostBack Then
            Dim oCtl As Object
            oCtl = LoadControl("~/Controls/UserControl1.ascx")

            oCtl.Id = "UserControl11"
            PlaceHolder1.Controls.Clear()
            PlaceHolder1.Controls.Add(oCtl)

            Session("ctl") = oCtl
        End If
    End Sub
End Class

这里是用户控件的完整代码

Partial Class UserControl1
    Inherits System.Web.UI.UserControl
    Protected Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click
        Label1.Text = "This is Text AFTER Post Back in User Control 1"
    End Sub
End Class

【讨论】:

【参考方案7】:

既然你问了,我会这样写你的初始化事件。我将把 Load 事件留作练习:

Protected Sub Page_Init(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Init
    If IsPostBack AndAlso Session("ctl") IsNot Nothing Then
        Dim MyControl As Control = Session("ctl")
        PlaceHolder1.Controls.Add(MyControl)
    End If
End Sub

我也会想出一个比“mycontrol”更好的名字,但是因为我不知道这个控件会做什么。

【讨论】:

但这实际上并不能解决我在控件内部的回发问题【参考方案8】:

如果不尝试我不知道,但是如果您以编程方式连接按钮的事件处理程序会怎样?例如,在用户控件本身的代码隐藏中,在 Init 或 Load 中(不确定):

AddHandler Button1.Click, AddressOf Button1_Click

如果这不起作用,我知道它的效率较低,但是如果您不将用户控件实例存储在 Session 中并且每次都在 Page_Init 中重新创建它怎么办?

【讨论】:

【参考方案9】:

您只想在不是 isPostBack 时加载控件

【讨论】:

以上是关于动态创建的用户控件无法处理 PostBack 上的事件的主要内容,如果未能解决你的问题,请参考以下文章

动态创建到 WPF 表单的用户控件上的按钮单击事件

为啥ASP.net中动态控件在刷新后不能

从 C# 上的函数处理程序访问表单控件

通过 Postback 在 UpdatePanel 中保留 DIV 的滚动位置

如何使用 jquery/javascript 捕获页面上的所有回发?

ASP.NET-POSTBACK是什么