【问题标题】:How to freeze freezable objects that cannot be frozen如何冻结无法冻结的可冻结对象
【发布时间】:2016-04-13 13:10:11
【问题描述】:

在我的场景中,我想在后台任务中渲染它之前冻结一个不变的 BitmapCacheBrush。不幸的是,我收到错误“无法冻结此 Freezable”。 是否有任何解决方法或hacky方式冻结也不是可冻结的对象? 也许可以通过反射设置正确的属性来达到这个目标?提前谢谢你们。

编辑:(我的示例代码按要求)

 public static class ext
{
    public static async Task<BitmapSource> RenderAsync(this Visual visual)
    {
        var bounds = VisualTreeHelper.GetDescendantBounds(visual);

        var bitmapCacheBrush = new BitmapCacheBrush(visual);
        bitmapCacheBrush.BitmapCache = new BitmapCache();

        // We need to disconnect the visual here to make the freezable freezable :). Of course this will make our rendering blank
        //bitmapCacheBrush.Target = null;

        bitmapCacheBrush.Freeze();

        var bitmapSource = await Task.Run(() =>
        {
            var renderBitmap = new RenderTargetBitmap((int)bounds.Width,
                                                         (int)bounds.Height, 96, 96, PixelFormats.Pbgra32);

            var dVisual = new DrawingVisual();
            using (DrawingContext context = dVisual.RenderOpen())
            {

                context.DrawRectangle(bitmapCacheBrush,
                                      null,
                                      new Rect(new Point(), new Size(bounds.Width, bounds.Height)));
            }

            renderBitmap.Render(dVisual);
            renderBitmap.Freeze();
            return renderBitmap;
        });

        return bitmapSource;
    }

}

【问题讨论】:

  • 你能提供一个最小的例子来说明你如何达到不可冻结的 BitmapCacheBrush 的地步吗?
  • 冻结无法冻结的对象的唯一方法是回到可以冻结的状态。然后它不再是一个“不可冻结”的对象,你又重新开始工作了。大多数情况下,当我看到这个问题时,这是因为有人试图从错误的线程中冻结对象。但是如果没有好的minimal reproducible example,就无法知道您在这里做错了什么,因此无法正确回答问题。

标签: c# wpf multithreading rendertargetbitmap freezable


【解决方案1】:

首先,您需要弄清楚为什么不能冻结它。进入注册表并将 ManagedTracing 设置为 1(如果必须设置,它是 REG_DWORD 类型)。我建议您将其添加到 regedit 中的收藏夹中,以便在需要打开/关闭它时快速访问它。

HKEY_CURRENT_USER\SOFTWARE\Microsoft\Tracing\WPF\ManagedTracing

当您尝试冻结 BitmapCacheBrush 或检查 bool 属性 BitmapCacheBrush.CanFreeze 时,您将在 Visual Studio 的“输出”选项卡中收到警告,告诉您问题所在。

我根据https://blogs.msdn.microsoft.com/llobo/2009/11/10/new-wpf-features-cached-composition/的代码做了一个测试用例

它给我的警告是:

System.Windows.Freezable 警告:2:CanFreeze 返回 false,因为 Freezable 上的 DependencyProperty 的值是 具有线程亲和性的 DispatcherObject; Freezable='System.Windows.Media.BitmapCacheBrush'; Freezable.HashCode='29320365'; Freezable.Type='System.Windows.Media.BitmapCacheBrush'; DP='目标'; DpOwnerType='System.Windows.Media.BitmapCacheBrush'; 值='System.Windows.Controls.Image'; Value.HashCode='11233554'; Value.Type='System.Windows.Controls.Image'

BitmapCacheBrush.Target 是 Visual 类型,所有 Visuals 都派生自 DependencyObject,而 DependencyObject 派生自 DispatcherObject。并根据https://msdn.microsoft.com/en-us/library/ms750441(v=vs.100).aspx#System_Threading_DispatcherObject

通过从 DispatcherObject 派生,您可以创建一个 CLR 对象,该对象具有 STA 行为,并将在创建时获得一个指向调度程序的指针 时间。

因此,所有视觉对象都是 STA,这意味着您无法冻结 BitmapCacheBrush,除非您将其 Target 设置为 null。

【讨论】:

    猜你喜欢
    • 2014-03-30
    • 1970-01-01
    • 1970-01-01
    • 2015-12-22
    • 1970-01-01
    • 1970-01-01
    • 2021-03-11
    • 1970-01-01
    • 2019-01-04
    相关资源
    最近更新 更多