22

我有一个 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视觉上的设置会影响它的孩子吗?还是我需要为每个子元素专门设置它?

4

3 回答 3

35

这是我们所做的:

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;
    }
}
于 2011-02-09T22:23:05.610 回答
24

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

RenderOptions.ProcessRenderMode = RenderMode.SoftwareOnly;

也可以在运行时切换

于 2012-06-13T09:32:00.293 回答
3

event -problem
对于缺少的 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);

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

于 2011-02-09T22:32:44.393 回答