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