关于 asp.net:动态创建的用户控件无法处理 PostBack 上的事件

关于 asp.net:动态创建的用户控件无法处理 PostBack 上的事件

User Control created dynamically not able to handle events on PostBack

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

1
2
3
4
5
6
Dim oCtl As Object
oCtl = LoadControl("~/Controls/UserControl1.ascx")

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

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


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

这些是:

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

    默认.aspx

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    %@ 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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    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

    1
    2
    3
    %@ 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

    1
    2
    3
    4
    5
    6
    7
    8
    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

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


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


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

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

    PlaceHolder1.Controls.Clear()

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

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


    几个问题:

  • 在页面生命周期的什么时候加载控件?
  • 事件处理程序代码在哪里?在控件本身还是您尝试将其连接到页面?
  • 到目前为止,你做了什么来完成这个活动?
  • 最后,.Net 的样式指南特别建议不要在 oCtl 中使用任何像 o 这样的匈牙利前缀疣,您应该将其键入为控件而不是对象。


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

    1
    AddHandler Button1.Click, AddressOf Button1_Click

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


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

    1
    2
    3
    4
    5
    6
    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"更好的名字,但是因为我不知道这个控件会做什么。


    这是页面的完整代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    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

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

    1
    2
    3
    4
    5
    6
    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

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


    推荐阅读