From my experience there are some situation in Windows Forms when disposed controls can be cached within the LayoutEventArgs
object and it looks like some kind of minor bug in WinForms.
Some details:
Each instance of the System.Windows.Forms.Control
type contains a private member variable of the LayoutEventArgs
type - cachedLayoutEventArgs
. And, the LayoutEventArgs
typically contains a reference to some specific control. You can clearly see all of these facts via Reflector. And, sometimes, the cachedLayoutEventArgs
field is not cleared when the child control disposing does not affect the layout process of the parent control sue to some reasons. You can imitate this situation using the mdi parent form by suspending the MdiClient's control layout while closing its children:
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 { }
There is a simple workaround - by triggering the PerformLayout
method, you can effectively flush-out that "cached" instance:
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;
}
}
}
P.S. In any way I suggest you contact the DevExpress support in this regard, to sure that the memory leak you described is not related to their controls and get the final solution.