I could actually solve the slow MDI performance with another more direct .NET approach, not requiring any compatibility flags.
The trick is to force double buffering onto the MdiClient
control (which is the container hosting the MDI windows).
The MdiClient
instance on the parent form can be retrieved by iterating through all its controls and checking for their type.
// Retrieve the MDI client control on this parent window.
MdiClient mdiClient = null;
foreach (Control control in Controls)
{
mdiClient = control as MdiClient;
if (mdiClient != null)
{
break;
}
}
Forcing double buffering is actually only possible by calling the protected method SetStyle
, so we have to use reflection to invoke it from outside. This seems really safe since SetStyle
is available since .NET 1.1 and has not changed since then.
// Force double buffering on it by calling the protected SetStyle method via reflection.
MethodInfo setStyleMethod = typeof(MdiClient).GetMethod("SetStyle",
BindingFlags.NonPublic | BindingFlags.Instance)
setStyleMethod.Invoke(mdiClient, object[] {
ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw,
true });
Performance is now as good as without any custom drawing.
Due to the ControlStyles.ResizeRedraw
parameter, the whole background gets repainted when the form size changes, useful if you plan to draw gradient backgrounds. Simply use the Paint
event on the MdiClient
instance and do your drawing there.
This also makes approaches to first draw everything on a bitmap unrequired, as double buffering already does that internally - getting rid of flickering along the way.
The only thing you might want to fix is to redraw the background when the MdiClient
is scrolled (when Windows are outside the visible area). This does not cause a Paint
event. This requires some more code, refer to these answers for it: How to detect when an MDIClient window has been scrolled and WinForms Layered Controls with Background images cause tearing while scrolling