ASP.net动态创建控件事件处理

时间:2009-07-18 07:13:46

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

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

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

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

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

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

当然,当我调用create()时,我将我的事件处理程序连接到复合控件的按钮单击事件。到现在为止还挺好。按下按钮后,按钮单击会按预期返回到控件。但是,事件永远不会返回到页面的事件处理程序。

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

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

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

谢谢!

添加说明:MyControl.Create()调用实际上会生成一个调用Composite Control的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
} 

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

4 个答案:

答案 0 :(得分:1)

您没有具体提到您在页面生命周期的哪个阶段创建并添加这些控件。要使回发起作用,必须在page_load事件之前完成所有创建(和连线)和“重新创建”。

在page_init处执行此操作,如果ID相同,则viewstate机制应接管回发值。

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

答案 1 :(得分:0)

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

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

答案 2 :(得分:0)

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

当你调用Create()时,你将初始化控件及其按钮,然后,当你知道按钮在那里时,挂钩事件处理程序,传递你到那里的参数。

MyControl : CompositeControl
{
    void Create(args, EventHandler click)
    {
        // init & set up your control

        // other processing

        MyButton.OnClick += click;
    }
}

答案 3 :(得分:0)

您应该始终将相同的ID添加到动态创建的控件中,如果您失败,有时控件事件不会被引发,

希望这有帮助。