根据我的经验,在 Windows 窗体中存在一些情况,当释放的控件可以缓存在LayoutEventArgs
对象中时,它看起来像是 WinForms 中的某种小错误。
一些细节:
该类型的每个实例都包含一个类型为 -System.Windows.Forms.Control
的私有成员变量。并且,通常包含对某些特定控件的引用。您可以通过 Reflector 清楚地看到所有这些事实。并且,有时,由于某些原因,子控件的处置不影响父控件的布局过程时,该字段没有被清除。您可以使用 mdi 父窗体通过暂停 MdiClient 的控件布局同时关闭其子窗体来模拟这种情况:LayoutEventArgs
cachedLayoutEventArgs
LayoutEventArgs
cachedLayoutEventArgs
public partial class MdiParentForm : Form {
public MdiParentForm () {
InitializeComponent(); // this.IsMdiContainer = true
}
void buttonAddMdiChild_Click(object sender, EventArgs e) {
MdiChildForm f = new MdiChildForm();
f.MdiParent = this;
f.Show();
}
void buttonCloseMdiChild_Click(object sender, EventArgs e) {
MdiClient client = GetMdiClient(this);
client.SuspendLayout();
if(ActiveMdiChild != null)
ActiveMdiChild.Close();
client.ResumeLayout(false);
// !!! At this point the MdiClient.cachedLayoutEventArgs contains the reference to disposed control (leak)
}
static MdiClient GetMdiClient(Form frm) {
if(frm != null) {
foreach(Control ctrl in frm.Controls) {
if(ctrl is MdiClient)
return (MdiClient)ctrl;
}
}
return null;
}
}
class MdiChildForm : Form { }
有一个简单的解决方法 - 通过触发该PerformLayout
方法,您可以有效地清除该“缓存”实例:
class MdiChildForm : Form {
MdiClient parent;
protected override void OnParentChanged(EventArgs e) {
base.OnParentChanged(e);
var mdiClient = Parent as MdiClient;
if(mdiClient != parent) {
if(parent != null)
parent.PerformLayout();
parent = mdiClient;
}
}
}
PS 无论如何我建议你在这方面联系DevExpress 支持,以确保你描述的内存泄漏与他们的控件无关并得到最终的解决方案。