1
votes

MDI applications are horribly slow since Windows Vista if Aero is turned on. Moving MDI windows around seems to lag noticably and the repainting is very slow.

Since Windows Vista, GDI is not hardware accelerated anymore to simplify the new graphic driver model. If you disable Aero (which you can't anymore in Windows 8), it's as fast as in Windows XP again.

With the Microsoft Application Compatibility Administrator, it is possible to set the "NoGdiHwAcceleration" flag which restores the MDI application speed even with Aero enabled.

However, no description was provided how to disable this acceleration programmatically or if this compatibility flag can be triggered by code.

Anyone knows how to?

2

2 Answers

0
votes

Have you tried using DwmEnableComposition and/or DwmEnableBlurBehindWindow? However, this does appear to disable Aero completely until the application exits or changes it back...

Also there's an answer here on SO that makes it look like you can switch to SW rendering per windows in .net 3.5 SP1 and up.

0
votes

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