动态加载带有事件处理程序的用户控件 - 取消注册。

5

我有一个表单,上面有一个面板,我会在这个面板上动态加载多个用户控件。我为每个控件处理事件。

UserControl userControl1 = LoadControl("control.ascx") as UserControl;
userControl1.Event += new ControlEventHandler(userControl_Event);
this.Panel.Controls.Add(userControl1);

UserControl userControl2 = LoadControl("control.ascx") as UserControl;
userControl2.Event += new ControlEventHandler(userControl_Event);
this.Panel.Controls.Add(userControl2);

...

现在当我删除面板上的控件时,我只需要执行以下操作:

this.Panel.Controls.Clear();

Clear()函数是否负责清除事件,还是我需要自己处理?

foreach(Control control in this.Panel.Controls)
{
    UserControl userControl = control as UserControl;
    if(userControl != null)
    {
        userControl -= userControl_Event;
    }
}

在清除Panel的内容之前,有什么需要注意的吗?

基本上,我正在寻找一种动态加载用户控件并处理其事件的方法,而不会在摆脱它们时创建泄漏。

谢谢!

编辑: 因为我的控件是在页面的Page_Init事件中动态创建的(每次都是如此),所以它们的生命周期不能比页面的生命周期更长,这样说是正确的吗? 据我所知,控件在回发后不存在。每次都会创建一个新的控件。因此,我不必注销事件,因为对象在下一个页面加载时甚至不存在。这是正确的吗?

5个回答

5
该页面将保留对动态实例化控件的引用,即使集合已被清除,这将防止控件被收集,直到页面本身被收集。
在这种特定情况下,这将很好地解决问题,因为页面的生命周期非常短。
然而,如果这是一个Windows窗体应用程序,那么内存将有效地泄漏,直到窗体被释放。
通常最好在释放事件所涉及的对象时取消订阅事件,因为这是大多数.NET内存泄漏的根源。

2
这是MSDN上回答您问题的页面: Control..::.ControlCollection..::.Clear Method 引用该页面的内容:
重要提示: 调用Clear方法不会从内存中删除控件句柄。您必须显式调用Dispose方法以避免内存泄漏。

0

说动态加载的用户控件的寿命不能比它所属的页面更长是正确的。但在从页面控件集合中移除Web控件并将其分配给一个如会话变量的对象时,我们不能说这是正确的,因为Web控件可以比页面寿命更长。所以这并不总是正确的。

如果您使用短寿命周期对象(例如页面、用户控件或Web控件等)的方法来订阅长寿命周期对象(例如单例对象或存储在asp.net中的应用程序、会话和缓存对象)的事件,则很重要的一点是您应该取消订阅事件。

例如:

UserControl uc = LoadControl("control.ascx") as UserControl;
SomeObject so=Session["SomeObject"] as SomeObject;
If(so!=null)
{
    so.SomeEvent += new SomeEventHandler(uc.SomeMethod);
}

这里应该取消订阅事件,以免造成内存泄漏。

最终,在您的情况下,您不必担心已注册的事件。它们将由垃圾收集器进行收集。


0

垃圾回收器应该能够在您不需要注销它们的情况下收集它们


0

你调用面板中的controls.Clear足以证明你应该注销事件。

为了做到这一点,你可以创建自己的控件集合,在重写的Clear方法中添加注销代码,然后创建自己的面板,使用从重写的Controls属性获取器返回的新集合。


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