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

时间:2022-03-23 13:21:37

I have a user control which is loaded in the page dynamically using the following code in Init of the Page.

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

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

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

The user control also contains a button and I am unable to capture the button click within the user control.

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

9 个解决方案

#1


10  

There are a couple of things which you are doing that are both not needed and probably causing your problems.

你正在做的一些事情都是不需要的,可能会引起你的问题。

These are:

  1. There is no need to store the control object in the session. The Control itself should use ViewState and Session State to store information as required, not the whole instance.
  2. 无需在会话中存储控制对象。 Control本身应该使用ViewState和Session State来存储所需的信息,而不是整个实例。

  3. You shouldn't be checking for PostBack when creating the control. It must be created each time to allow both ViewState to work and the event to be wired.
  4. 创建控件时,不应检查PostBack。每次都必须创建它以允许ViewState工作和事件连线。

  5. Controls loaded after the ViewState is loaded often have trouble operating correctly so avoid loading during the Page Load event wherever possible.
  6. 加载ViewState后加载的控件通常无法正常运行,因此请尽可能避免在Page Load事件期间加载。

This code works for me:

这段代码适合我:


Default.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>

Default.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


5  

You have to ensure that the control exists on the page prior to .NET entering the "Postback event handling" step of the page lifecycle. Since the control is added dynamically you have to ensure that on every post back you recreate that control so that it can find the control to fire the event.

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

#3


3  

Make sure you load the control on every postback - if the control isn't in the tree of controls when the page posts back, ASP.NET will not raise the button click event.

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

#4


2  

I just experienced similar problem as you did, except that in my case i didn't used a session to store the control.

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

In my case, i located the problem in this line:

在我的情况下,我找到了这一行中的问题:

PlaceHolder1.Controls.Clear()

What i did is created a child controls and added them to the parent container on Page_Init, then processed some event handlers and after that on Page_PreRender i recreated the whole list again with the updated data.

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

The solution i used in this case was to create the control collection once - in the early phase of the page cycle.

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

#5


1  

A few questions:

几个问题:

  1. At what point in the page lifecycle do you load the control?
  2. 在页面生命周期的什么时候加载控件?

  3. Where is the event handler code? In the control itself or do you try to hook it up to the page?
  4. 事件处理程序代码在哪里?在控件本身或您是否尝试将其连接到页面?

  5. What have you done so far to wire up the event?
  6. 你到目前为止做了什么事情来搞活事件?

Finally, the style guidelines for .Net specifically recommend against using any hugarian prefix warts like the o in oCtl, and you should type it as a Control rather than an object.

最后,.Net的样式指南特别建议不要使用像oCtl中的o那样的任何hugarian前缀疣,你应该将它键入为Control而不是对象。

#6


0  

Here is the complete code for the Page

这是Page的完整代码

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

Here is the complete code for the user Control

以下是用户Control的完整代码

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


0  

Since you asked, I'd write your init event like this. I'll leave the Load event as an exercise:

既然你问过,我会像这样写你的init事件。我将把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

I'd also come up with a better name than 'mycontrol', but since I don't know what the control does this will have to do.

我也想出一个比'mycontrol'更好的名字,但是因为我不知道控件的作用是什么。

#8


0  

I don't know without trying it, but what if you programatically wire up the button's event handler? For instance, in the code-behind for the User Control itself, in Init or Load (not sure):

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

AddHandler Button1.Click, AddressOf Button1_Click

If that doesn't do anything, I know it's less efficient, but what if you don't store the User Control instance in Session and always recreate it in Page_Init every time?

如果这没有做任何事情,我知道效率较低,但如果你没有在Session中存储User Control实例并且每次都在Page_Init中重新创建它会怎样?

#9


-1  

You want to only load the control when not isPostBack

您希望仅在不是isPostBack时加载控件

#1


10  

There are a couple of things which you are doing that are both not needed and probably causing your problems.

你正在做的一些事情都是不需要的,可能会引起你的问题。

These are:

  1. There is no need to store the control object in the session. The Control itself should use ViewState and Session State to store information as required, not the whole instance.
  2. 无需在会话中存储控制对象。 Control本身应该使用ViewState和Session State来存储所需的信息,而不是整个实例。

  3. You shouldn't be checking for PostBack when creating the control. It must be created each time to allow both ViewState to work and the event to be wired.
  4. 创建控件时,不应检查PostBack。每次都必须创建它以允许ViewState工作和事件连线。

  5. Controls loaded after the ViewState is loaded often have trouble operating correctly so avoid loading during the Page Load event wherever possible.
  6. 加载ViewState后加载的控件通常无法正常运行,因此请尽可能避免在Page Load事件期间加载。

This code works for me:

这段代码适合我:


Default.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>

Default.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


5  

You have to ensure that the control exists on the page prior to .NET entering the "Postback event handling" step of the page lifecycle. Since the control is added dynamically you have to ensure that on every post back you recreate that control so that it can find the control to fire the event.

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

#3


3  

Make sure you load the control on every postback - if the control isn't in the tree of controls when the page posts back, ASP.NET will not raise the button click event.

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

#4


2  

I just experienced similar problem as you did, except that in my case i didn't used a session to store the control.

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

In my case, i located the problem in this line:

在我的情况下,我找到了这一行中的问题:

PlaceHolder1.Controls.Clear()

What i did is created a child controls and added them to the parent container on Page_Init, then processed some event handlers and after that on Page_PreRender i recreated the whole list again with the updated data.

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

The solution i used in this case was to create the control collection once - in the early phase of the page cycle.

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

#5


1  

A few questions:

几个问题:

  1. At what point in the page lifecycle do you load the control?
  2. 在页面生命周期的什么时候加载控件?

  3. Where is the event handler code? In the control itself or do you try to hook it up to the page?
  4. 事件处理程序代码在哪里?在控件本身或您是否尝试将其连接到页面?

  5. What have you done so far to wire up the event?
  6. 你到目前为止做了什么事情来搞活事件?

Finally, the style guidelines for .Net specifically recommend against using any hugarian prefix warts like the o in oCtl, and you should type it as a Control rather than an object.

最后,.Net的样式指南特别建议不要使用像oCtl中的o那样的任何hugarian前缀疣,你应该将它键入为Control而不是对象。

#6


0  

Here is the complete code for the Page

这是Page的完整代码

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

Here is the complete code for the user Control

以下是用户Control的完整代码

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


0  

Since you asked, I'd write your init event like this. I'll leave the Load event as an exercise:

既然你问过,我会像这样写你的init事件。我将把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

I'd also come up with a better name than 'mycontrol', but since I don't know what the control does this will have to do.

我也想出一个比'mycontrol'更好的名字,但是因为我不知道控件的作用是什么。

#8


0  

I don't know without trying it, but what if you programatically wire up the button's event handler? For instance, in the code-behind for the User Control itself, in Init or Load (not sure):

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

AddHandler Button1.Click, AddressOf Button1_Click

If that doesn't do anything, I know it's less efficient, but what if you don't store the User Control instance in Session and always recreate it in Page_Init every time?

如果这没有做任何事情,我知道效率较低,但如果你没有在Session中存储User Control实例并且每次都在Page_Init中重新创建它会怎样?

#9


-1  

You want to only load the control when not isPostBack

您希望仅在不是isPostBack时加载控件