How to freeze freezable objects that cannot be frozen
Asked Answered
R

1

6

In my scenario I want to freeze a non changing BitmapCacheBrush before I want to render it in a background task. Unfortunately I receive the error "This Freezable cannot be frozen". Is there any workaround or hacky way freeze also not freezable objects? Maybe it is possible to set the right properties via reflection to reach this goal? Thank you guys in advance.

Edit: (My sample code as requested)

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

}
Reliquary answered 13/4, 2016 at 13:10 Comment(2)
Can you provide minimal example of how to you get to the point of non-freezable BitmapCacheBrush?Riggall
The only way to freeze an object that cannot be frozen is to get back into a state where it can be frozen. Then it is no longer an "unfreezable" object and you're back in business. Most often when I see this problem, it's because one is attempting to freeze the object from the wrong thread. But without a good minimal reproducible example there's no way to know what you've done wrong here, so no way to answer the question correctly.Corenecoreopsis
T
7

First, you need to figure out WHY you can't freeze it. Get into the registry and set ManagedTracing to 1 (if you have to make it, it's a REG_DWORD type). I suggest you add it to your Favorites in regedit so you can quickly get to it when you need to turn it on/off.

HKEY_CURRENT_USER\SOFTWARE\Microsoft\Tracing\WPF\ManagedTracing

When you try to freeze the BitmapCacheBrush or check the bool property BitmapCacheBrush.CanFreeze, you will get a warning in the Output tab in visual studio telling you what the problem is.

I made a test case based off code from https://blogs.msdn.microsoft.com/llobo/2009/11/10/new-wpf-features-cached-composition/

And the warning it gave me was:

System.Windows.Freezable Warning: 2 : CanFreeze is returning false because a DependencyProperty on the Freezable has a value that is a DispatcherObject with thread affinity; Freezable='System.Windows.Media.BitmapCacheBrush'; Freezable.HashCode='29320365'; Freezable.Type='System.Windows.Media.BitmapCacheBrush'; DP='Target'; DpOwnerType='System.Windows.Media.BitmapCacheBrush'; Value='System.Windows.Controls.Image'; Value.HashCode='11233554'; Value.Type='System.Windows.Controls.Image'

BitmapCacheBrush.Target is of type Visual and all Visuals are derived from DependencyObject which is derived from DispatcherObject. And according to https://msdn.microsoft.com/en-us/library/ms750441(v=vs.100).aspx#System_Threading_DispatcherObject

By deriving from DispatcherObject, you create a CLR object that has STA behavior, and will be given a pointer to a dispatcher at creation time.

So, all Visuals are STA which means you can't freeze BitmapCacheBrush unless you set it's Target to null.

Tonneson answered 13/4, 2016 at 15:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.