【问题标题】:Software rendering mode - WPF软件渲染模式 - WPF
【发布时间】:2011-06-24 11:26:44
【问题描述】:

我有一个 WPF 用户控件,我需要在 RenderMode.SoftwareOnly 中强制呈现它。由于我使用的是 .NET 3.5,所以我不得不这样做:

var hwndSource = PresentationSource.FromVisual(this) as HwndSource;
if (hwndSource != null)
{
    hwndSource.CompositionTarget.RenderMode = RenderMode.SoftwareOnly;        
}

但这不适用于我的应用程序,WPF 程序在少数机器上崩溃,在注册表级别关闭硬件加速似乎可以解决问题。

上面的代码写在窗口的Loaded事件中。如果我是正确的,Loaded 事件会在控件呈现后发生 (MSDN)。那么在该事件中使用上述代码是否有意义?如果不是,哪个活动适合它?

另外,在视觉对象上设置RenderMode 会影响其子对象吗?还是我需要为每个子元素专门设置这个?

【问题讨论】:

  • 嗨,我很好奇。调度程序解决方案对您有帮助吗?

标签: c# .net wpf .net-3.5 hardware-acceleration


【解决方案1】:

这是我们所做的:

private void Window_Loaded(object sender, RoutedEventArgs e)
{
    if (ForceSoftwareRendering)
    {
        HwndSource hwndSource = PresentationSource.FromVisual(this) as HwndSource;
        HwndTarget hwndTarget = hwndSource.CompositionTarget;
        hwndTarget.RenderMode = RenderMode.SoftwareOnly;
    }
}

它对我们来说工作正常,除了...这需要为每个窗口完成。在 .NET 3.5 中,无法使设置在应用程序范围内生效。还有一些窗口是您无法控制的——例如,右键单击“上下文”窗口。我们发现.NET 3.5除了注册表设置没有好的解决方案。

已编辑

这是我们用来确定何时强制软件渲染的逻辑。这是由 Microsoft 支持工程师建议的。

public bool ForceSoftwareRendering 
{
    get 
    { 
        int renderingTier = (System.Windows.Media.RenderCapability.Tier >> 16);
        return renderingTier == 0;
    }
}

在 .NET 4 中,Microsoft 添加了一个非常适合我们的应用程序范围设置。这是一个更好的选择,因为您不需要在每个窗口上都设置它。您只需设置一次,即可应用于所有窗口。

System.Windows.Media.RenderOptions.ProcessRenderMode

已编辑

新的 .NET 4.0 属性可以像这样在应用程序启动时设置:

public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs e)
    {
        if (ForceSoftwareRendering)
            RenderOptions.ProcessRenderMode = RenderMode.SoftwareOnly;
    }
}

【讨论】:

  • “ForceSoftwareRendering”从何而来?您是否找到了一种方法来检测哪些机器会因软件渲染而崩溃?
  • @EduardoWada 我将更新答案以包含此内容。
  • 除了 WinForms 有没有人知道同样的事情?
  • @user1722669,WinForms 无法使用硬件加速。
  • 我的 WPF 应用程序出现渲染问题,使用 SoftwareOnly 解决了这些问题。但是,System.Windows.Media.RenderCapability.Tier 为这台机器返回 0x20000,因此检查表明该机器应该支持它。
【解决方案2】:

您还可以通过将下一行放在应用程序启动处理程序中来禁用整个进程的硬件渲染:

RenderOptions.ProcessRenderMode = RenderMode.SoftwareOnly;

运行时也可以切换

【讨论】:

  • +1 表示可以在运行时切换。这在 MSDN 中不是很明显,但它是重要的信息。
【解决方案3】:

事件-问题
对于缺少的 hwnd-source,请尝试以下操作:

    Dispatcher.BeginInvoke(new Action(delegate {               
       HwndSource hwndSource = PresentationSource.FromVisual(this) as System.Windows.Interop.HwndSource;
            if (null == hwndSource) {
                throw new InvalidOperationException("No HWND");
            }
            HwndTarget hwndTarget = hwndSource.CompositionTarget;
            hwndTarget.RenderMode = RenderMode.SoftwareOnly;

  }),System.Windows.Threading.DispatcherPriority.ContextIdle, null);

渲染模式的范围
据我所知,每个 WPF 窗口只有一个 Win32 窗口,其余的都在 WPF 中呈现为原生。这就是为什么我认为设置RenderMode 涉及视觉对象所在窗口中的所有内容。在这种情况下,范围是窗口范围。

【讨论】:

  • 谢谢。你能解释一下为什么在这种情况下需要 Dispatcher 吗?
  • @appu:这不是必需的 - 但是如果在加载事件的执行时 hwnd 不存在(如果这是问题),那么显式等待系统完成所有这很重要任务(例如渲染:)可能会有所帮助。我已经看到了很多不常见的场景,这些问题可以通过这种方式解决。但这只是一个想法,我不能保证它有效。顺便说一句,我在没有调度程序的情况下使用上面的代码,到目前为止还没有问题。但我只在一个应用程序中使用它,这是一个很少使用的选项。因此,这种说法肯定不具有代表性。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-12-30
  • 2010-09-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-10
相关资源
最近更新 更多