【问题标题】:Disabling GDI "hardware acceleration" in WinForms MDI with Aero for speed up在带有 Aero 的 WinForms MDI 中禁用 GDI“硬件加速”以加快速度
【发布时间】:2014-07-27 15:34:44
【问题描述】:

如果打开 Aero,MDI 应用程序从 Windows Vista 开始会非常慢。移动 MDI 窗口似乎明显滞后,并且重绘非常缓慢。

从 Windows Vista 开始,GDI 不再进行硬件加速以简化新的图形驱动程序模型。如果您禁用 Aero(在 Windows 8 中不能再这样做),它的速度将再次与 Windows XP 一样快。

使用 Microsoft 应用程序兼容性管理器,可以设置“NoGdiHwAcceleration”标志,即使启用 Aero 也能恢复 MDI 应用程序速度。

但是,没有说明如何以编程方式禁用此加速,或者此兼容性标志是否可以由代码触发。

有人知道怎么做吗?

【问题讨论】:

    标签: winforms gdi mdi hardware-acceleration aero


    【解决方案1】:

    您是否尝试过使用DwmEnableComposition 和/或DwmEnableBlurBehindWindow?但是,这似乎会完全禁用 Aero,直到应用程序退出或将其更改回来......

    还有一个 answer here on SO,看起来您可以在 .net 3.5 SP1 及更高版本中切换到每个窗口的 SW 渲染。

    【讨论】:

    • Aero dwmapi 方法在这里没有帮助,因为它们只是将玻璃扩展到客户区域。此外,EnableComposition 自 Win8 以来不再有效,并且它还会在系统范围内禁用整个 Aero 界面,这不是我想要的。您提到的硬件加速与 WPF 有关,而不是 WinForms 和 GDI。
    • 哦,您在问题中提到了 Windows 8,但我不知道您使用的是什么。如果是这样的话,我不相信这是可能的。
    • 是的,我不喜欢从一开始就在 Windows 7 / Vista 中禁用 Aero 的应用程序:D
    【解决方案2】:

    我实际上可以使用另一种更直接的 .NET 方法来解决缓慢的 MDI 性能,而不需要任何兼容性标志。

    诀窍是对MdiClient 控件(即托管MDI 窗口的容器)强制进行双重缓冲。

    父表单上的MdiClient 实例可以通过遍历其所有控件并检查其类型来检索。

    // 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;
        }
    }
    

    强制双缓冲实际上只能通过调用受保护的方法SetStyle来实现,所以我们必须使用反射从外部调用它。这似乎非常安全,因为 SetStyle 从 .NET 1.1 开始可用,并且从那时起就没有改变。

    // 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 });
    

    性能现在与没有任何自定义绘图一样好。

    由于ControlStyles.ResizeRedraw 参数,当表单大小发生变化时,整个背景会被重新绘制,这在您计划绘制渐变背景时很有用。只需在 MdiClient 实例上使用 Paint 事件并在那里进行绘图。

    这也使得首先在位图上绘制所有内容的方法不再是必需的,因为双缓冲已经在内部做到这一点 - 消除了沿途的闪烁。

    您可能想要解决的唯一问题是在滚动MdiClient 时重绘背景(当 Windows 位于可见区域之外时)。这不会导致Paint 事件。这需要更多代码,请参考以下答案:How to detect when an MDIClient window has been scrolledWinForms Layered Controls with Background images cause tearing while scrolling

    【讨论】:

      猜你喜欢
      • 2011-01-11
      • 1970-01-01
      • 2015-03-16
      • 1970-01-01
      • 1970-01-01
      • 2011-09-20
      • 2012-03-09
      • 1970-01-01
      • 2011-06-05
      相关资源
      最近更新 更多