C# 如何冻结无法冻结的可冻结对象

C# 如何冻结无法冻结的可冻结对象,c#,wpf,multithreading,rendertargetbitmap,freezable,C#,Wpf,Multithreading,Rendertargetbitmap,Freezable,在我的场景中,我希望在后台任务中渲染未更改的BitmapCacheBrush之前将其冻结。不幸的是,我收到了错误“此Freezable无法冻结”。 是否有任何解决方法或黑客方式冻结也不能冻结的对象? 也许可以通过反射设置正确的属性来达到这个目标?提前谢谢你们 编辑:(我的样本代码按要求) 公共静态类ext { 公共静态异步任务RenderAsync(此可视化) { var bounds=VisualTreeHelper.GetGenderantBounds(可视); var bitmapCach

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

编辑:(我的样本代码按要求)

公共静态类ext
{
公共静态异步任务RenderAsync(此可视化)
{
var bounds=VisualTreeHelper.GetGenderantBounds(可视);
var bitmapCacheBrush=新的bitmapCacheBrush(可视);
bitmapCacheBrush.BitmapCache=新的BitmapCache();
//我们需要在此处断开视觉连接,以使freezable:)。当然,这将使渲染为空白
//bitmapCacheBrush.Target=null;
bitmapCacheBrush.Freeze();
var bitmapSource=等待任务。运行(()=>
{
var renderBitmap=新的RenderTargetBitmap((int)bounds.Width,
(int)bounds.Height,96,96,PixelFormats.Pbgra32);
var dVisual=新绘图可视化();
使用(DrawingContext=dVisual.renderropen())
{
context.DrawRectangle(bitmapCacheBrush,
无效的
新矩形(新点(),新大小(bounds.Width,bounds.Height));
}
renderBitmap.Render(dVisual);
renderBitmap.Freeze();
返回renderBitmap;
});
返回位图源;
}
}

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

HKEY\U当前\U用户\SOFTWARE\Microsoft\Tracing\WPF\ManagedTracing

当您尝试冻结BitmapCacheBrush或检查bool属性BitmapCacheBrush.CanFreeze时,visual studio的“输出”选项卡中将显示一条警告,告诉您问题所在

我根据源代码制作了一个测试用例

它给我的警告是:

System.Windows.Freezable警告:2:CanFreeze返回false,因为Freezable上的DependencyProperty的值为 具有线程关联的DispatcherObject; 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的类型为Visual,所有视觉效果都派生自DependencyObject,DependencyObject派生自DispatcherObject。根据

通过从DispatcherObject派生,可以创建具有 STA行为,并将在创建时提供指向调度程序的指针 时间


因此,所有的视觉效果都是STA,这意味着您不能冻结BitmapCacheBrush,除非您将其目标设置为null。

您能提供如何达到不可冻结BitmapCacheBrush点的最低示例吗?冻结无法冻结的对象的唯一方法是将其恢复到可以冻结的状态。然后,它不再是一个“不可冻结”的对象,你又回到了业务中。大多数情况下,当我看到这个问题时,是因为试图从错误的线程冻结对象。但是如果没有一个好的答案,就无法知道你在这里做错了什么,因此也无法正确回答这个问题。
 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;
    }

}