【问题标题】:ASP.net dynamically created control event handlingASP.net 动态创建控件事件处理
【发布时间】:2009-07-18 07:13:45
【问题描述】:

基本上我在页面加载时动态添加了一个占位符。

然后我有一个复合控件添加到占位符并在运行时显示特定页面事件。复合控件有一个按钮。我有一个用于复合控件中可用按钮的公共事件处理程序,但实际上并没有直接访问页面代码中的此事件处理程序。

要显示控件,我会进行以下调用:

MyControl.Create(args, new EventHandler(OnClick)); 

然后在页面上我会有protected void OnClick(object o, EventArgs args) {}

当然,当我调用create() 时,我会将我的事件处理程序连接到复合控件的按钮单击事件。到目前为止,一切都很好。连接按钮后,按钮单击按预期返回到控件。但是,该事件永远不会返回到页面的事件处理程序。

我意识到问题是在回发时发生的。然而,尝试在 init、load 或 createchildcontrols 上连接按钮都无法保持连接到位,因此可以在页面上处理事件。我想要的是能够在运行时将事件处理程序传递给复合控件,并让复合控件在回发时正确地将事件发送回页面。

有趣的是,如果我使用自定义事件参数调用 OnBubble,我可以捕获页面上的冒泡事件。但问题是我的占位符在页面上,所以当我尝试在 UserControl 中调用 MyControl.Create() 时,例如,气泡会转到页面而不是 UserControl(如预期的那样)。因此,我更喜欢声明事件处理程序而不是覆盖OnBubble 的原因(UserControls 和其他声明 MyControl 的控件基本上会使它对按钮单击事件无用)。

我希望有人对这个问题有所了解。这似乎是一个有趣的问题,但除了在页面上显式声明控件并在标记或页面加载中直接连接事件之外,可能没有其他解决方案。我会考虑让按钮进行异步回调,但如果可能的话,我更愿意使用标准的 ASP.NET 事件处理。

谢谢!

补充说明:MyControl.Create() 调用实际上生成了一个事件,该事件调用了复合控件的Create() 方法。这一切都很好,但值得注意的是MyControl.Create() 方法无法直接访问控件。这应该是有道理的,因为控件被添加到页面onload 上而不是在标记中。

更多代码:

MyControl : CompositeControl 
{
     public event EventHandler Click;

     //I have a create method
     void Create(args, EventHandler click)
     {
          this.Click = click;
          //other processing
     }

     //then the button is wired up. I've tried in OnInit(), OnLoad()
     void CreateChildControls()
     {
           MyButton.OnClick += Click;
     }

     //if I wire up the button to a default handler I can check if
       Click is not null and send the click event onto the next handler 
     //this is where the bubble event works, but the wiring fails
} 

编辑:我尝试将事件处理程序存储在 Session 中并在回发时连接按钮是成功的。我不认为这是一种好的做法,我认为它实际上并没有达到我的目的。例如,在这种情况下,页面上的事件按预期执行,但具有非标准页面行为。例如, Response.Redirect() 会引发异常。这应该是有道理的,因为事件处理程序可能在回发期间丢失了状态信息。 几个想法: 1.我是否可以创建一个与此控件相关的自定义气泡事件?这似乎是合理的,但是页面回发的问题再次让我遇到了同样的问题,即气泡应该去哪里。那么,当我调用 create() 时,是否可以自动将 UserControl 注册为气泡的目的地?似乎很难。 2. 在页面生命周期中的某个时刻,我可以在 UserControl 声明的事件处理程序上重新连接事件,以便在回发时正确调用委托?这似乎是我所缺少的。事件处理程序是在回发时创建的,但由于在 OnClick 期间未在 UserControl 中重新创建而丢失。我不希望 UserControl 必须显式地重新创建事物,而是希望子控件为 UserControl 重新创建它。这听起来像是一个简单的请求,但是如果 UserControl 不在循环中,我可能会要求不可能的事情。

【问题讨论】:

  • 您能在实际连接处理程序的地方发布更多代码吗?
  • 我很确定您通过在其中存储事件处理程序来泄漏内存;)

标签: asp.net user-controls composite event-handling


【解决方案1】:

您没有具体提及您在页面生命周期的哪个时间点创建和添加这些控件。为了使回发工作正常,所有创建(和连接)和“重新创建”都必须在 page_load 事件之前完成。

在 page_init 处执行,如果 ID 相同,则视图状态机制应接管回发值。

我在这里遇到了另一种方法: http://www.codeproject.com/KB/viewstate/retainingstate.aspx

【讨论】:

    【解决方案2】:

    您将控件动态插入占位符的动机是什么?请求之间并不真正存在页面,因此任何动态插入的控件都无法生存。你基本上必须伪造它。

    您可能要考虑的一个选项是编写具有不同呈现模式但具有一致事件接口的自定义控件。另一种是使用 ASP.NET MultiView 控件,它只会在 HTML 中呈现可见视图,但仍会在不可见视图中维护事件处理程序。

    【讨论】:

    • 感谢您的回复。该控件经常在许多应用程序和几乎所有页面中使用尝试将控件动态插入页面的主要动机是我们可以使用 httpmodule 使用 .config 文件中的单行插入控件...所以为了便于开发、便于代码重用和更好的页面可维护性。我很欣赏这些建议,并将对其进行更多研究。如果我找到可以在那里使用的解决方案,我会回复。
    【解决方案3】:

    好的,如果我错了,请纠正我,您的 Create() 方法实际上会实例化并将您的内部控件设置为已知状态;我看到你已经有了对按钮的引用,那为什么此时还需要一个额外的 Click 事件呢?

    当您调用 Create() 时,您将初始化控件及其按钮,然后,当您知道按钮在那里时,连接您的事件处理程序并传递您获得的参数。

    MyControl : CompositeControl
    {
        void Create(args, EventHandler click)
        {
            // init & set up your control
    
            // other processing
    
            MyButton.OnClick += click;
        }
    }
    

    【讨论】:

    • 事件处理程序本身在父页面或用户控件上声明。实际上不需要额外的事件处理程序,但是因为这个在回发时会丢失,所以我确实在控件中编写了一个,以便我可以捕获事件并调用 OnBubble。我确实注意到,如果我将事件处理程序存储在 session 中并重新连接 oninit 或 onload Page 或 UserControl 将捕获事件,但不会处于稳定状态。
    【解决方案4】:

    您应该始终为动态创建的控件放置相同的 ID,如果您失败了,有时控件事件不会引发,

    希望对您有所帮助。

    【讨论】:

      猜你喜欢
      • 2013-04-21
      • 1970-01-01
      • 2011-01-01
      • 1970-01-01
      • 2012-03-18
      • 1970-01-01
      • 2010-11-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多