动态创建的控件事件处理程序未触发

9

我有一个动态创建的文本框的问题。

当文本框在PageLoad中被创建时,它的TextChanged事件被触发。
但是当我动态删除并重新创建文本框时,TextChanged事件没有被触发。

这是代码:

.aspx文件

<body>
    <form id="form1" runat="server">
    <div>

    <asp:Table ID="Table1" runat="server">
      <asp:TableRow>
        <asp:TableCell ColumnSpan="2">Fixed content</asp:TableCell>
      </asp:TableRow>
    </asp:Table>   
    </form>
</body>

.cs file

public partial class test : System.Web.UI.Page
{
  string myText = "a";

  protected void Page_Load(object sender, EventArgs e)
  {
    WriteRows();
  }

  private void WriteRows()
  {
    TableRow tr = new TableRow();

    TableCell tc = new TableCell();
    TextBox txt = new TextBox();
    txt.Text = myText;
    txt.TextChanged += new EventHandler(txt_TextChanged); // Assign event handler
    tc.Controls.Add(txt);
    tr.Controls.Add(tc);

    tc = new TableCell();
    tc.Text = txt.Text;
    tr.Controls.Add(tc);

    Table1.Controls.AddAt(1, tr);
  }

  private void txt_TextChanged(object sender, EventArgs e)
  {
    myText = ((TextBox)sender).Text;
    RedrawTable(); // Delete the row (incl. the TextBox) and rewrite it
  }

  private void RedrawTable()
  {
    Table1.Controls.RemoveAt(1);
    WriteRows();
  }
}

有没有解决方案可以使事件始终被触发?

你解决了你的问题吗?我也遇到了动态创建的ASP按钮相同的问题。我给按钮设置了ID,但是没有任何结果。 - Nurlan
11个回答

12

ASP.NET通过匹配控件的ID和请求参数来处理事件处理。在您的情况下,由于您没有指定任何显式ID,因此在txtTextChanged()期间创建的TextBox将具有自动ID。该ID将在文本更改事件期间发布。

在页面加载事件之后,ASP.NET将尝试查找具有此类ID的控件以触发其事件。显然,ASP.NET无法找到匹配项,因为在Page_Load()期间创建的TextBox是不同的,并且具有不同的ID。

要解决此问题:为文本框指定显式ID:

TextBox txt = new TextBox();
txt.Text = myText;
txt.ID = "txtBox";

+1 我相信这是我动态创建的控件和此代码片段中指定的控件之间唯一的区别。我做了这样的事情:txt.ID = String.Format("txtUserId_{0}", id) - Astra
@BryanRehbein M也分配了ID,但事件仍然没有触发,m在.net 2.0框架上。 - 1Mayur
我遇到了与动态创建的ASP按钮相同的问题。我为按钮设置了ID,但这并没有产生任何结果。 - Nurlan

3
尝试在Page_Init()方法中创建控件...

2

为了触发PostBack事件,应该触发事件的控件需要在PostBack生命周期中以相同的ID和相同的数据可用。

如果您有静态控件(在aspx / ascx / master中定义),并且ViewState已打开,则它们将自动重新创建。

如果您不想使用ViewState或使用动态控件,则需要在每个Page_Load上绑定控件,以便控件及时启动以触发事件(发生在Page_Load之后)。

如果更改父控件或页面的ID,则可能会意外地扰乱ViewState自动绑定,因为控件ID包含祖先ID。我认为只要在Page_Init(在设置ViewState之前)中进行操作,就应该是安全的。


2
在Page_Init中重新创建动态创建的控件。如果在Page_Load中重新创建控件,则无法访问控件的视图状态数据(视图状态在PreLoad中加载,而PreLoad发生在Page_Load之前)。
此外,不要忘记为控件分配一个ID。

1
我曾经遇到过类似的问题。我认为问题在于动态创建的控件不会被保存在视图状态中,也不会在 postback 后保留下来。以下是我从代码中摘取的注释,描述了我想出的解决方案(可能不是唯一的解决方法,但对我很有效)。
此页面用于动态定义网格。用户单击复选框以指示将哪些字段包括在网格中。这个页面的逻辑有两个基本部分:
1. 它维护 GridDefinition 对象,该对象保存在 ViewState 中。 2. 它根据 ViewState 中的 GridDefinition 在每次 postback 时重构以编程方式添加的控件(实际上是表对象中的所有内容)。动态添加的控件不会在 postback 时重新创建。事实上,我发现如果您不重新创建控件,则它们的事件将无法触发。显然:
       "The process that matches controls to posted values occurs 
       after page_load completes, so it has to occur just like this 
       if you are to use this way."

当我收到控件事件指示数据发生变化时,我必须在ViewState中存储的GridDefinition对象中反映该变化。这样,在下一次postback时,控件可以被正确地重新创建(例如,指示网格列标题文本的文本框)。

0
当我研究这个问题时,它是在动态菜单的背景下,有一堆谷歌的回应,共同帮助我解决了它(因为我猜这是一个足够常见的需求)。我没有答案的摘要,但这可能是一个有用的起点(即搜索“Dynamic Menus .NET”)。这个网站上也有几个相关问题。

0
作为另一个建议,绑定事件在 Page_Load 之后不是太晚了吗?因此它们在 postback 上不会被触发。也许需要检查一下。

在我的asp.net代码中,我可以通过Page_Load绑定事件到动态创建的控件,但是Page_LoadComplete太晚了,绑定的事件将不会触发。 - Astra

0

我再次想起为什么我避免使用asp - 对我来说,它似乎是多了一层抽象。但是根据javascript的类比,你可能会在事件上得到多个处理程序吗?


0

您只需要为文本框分配一个ID属性即可。这样应该可以解决您的问题。


0

我曾经遇到过同样的问题,在我的情况下,txt.AutoPostBack = true 是我忘记的。默认值为false,很容易被忽略。


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