Wpf 在可视化树中移动UIElement而不重新计算布局

Wpf 在可视化树中移动UIElement而不重新计算布局,wpf,.net-4.0,visual-tree,Wpf,.net 4.0,Visual Tree,我们有一个使用停靠控件(Actipro)的WPF应用程序(.Net 4.0)。我们可以在对接窗口外对接。在这种情况下,将创建一个“真实”窗口,并将内容分配给该窗口 当然,在视觉树中移动内容将重新触发整个布局。这是有问题的,因为在其中一个停靠窗口中,我们有一个图表控件(Mindfusion图表,WPF控件),它最多需要10秒来完成自身布局(非常大的图表) 我认为这个问题没有任何直接的解决办法。然而,我想知道其他有类似问题的程序员是如何处理这个问题的。有没有聪明的方法避免重新计算布局 理论上,由于图

我们有一个使用停靠控件(Actipro)的WPF应用程序(.Net 4.0)。我们可以在对接窗口外对接。在这种情况下,将创建一个“真实”窗口,并将内容分配给该窗口

当然,在视觉树中移动内容将重新触发整个布局。这是有问题的,因为在其中一个停靠窗口中,我们有一个图表控件(Mindfusion图表,WPF控件),它最多需要10秒来完成自身布局(非常大的图表)

我认为这个问题没有任何直接的解决办法。然而,我想知道其他有类似问题的程序员是如何处理这个问题的。有没有聪明的方法避免重新计算布局

理论上,由于图表位于ScrollViewer中,因此实际上没有任何变化,因此无论何时放置,可用空间量都保持不变(无限)


编辑:还要注意,内部的图控件是交互式的。我们需要拖放

您可能希望用图像替换可视化树中的图表控件,在屏幕外渲染图表,并使用rendertargetbitmap将渲染的图表转换为图像,该图像可以用作可视化树中图像的源

大概是这样的:

// image is the Image from the visual tree
int h = image.ActualHeight;
int w = image.ActualWidth;

// layout the diagram to the size of the image
diagram.Measure(new Size(w, h));
diagram.Arrange(new Rect(newSize(w,h)));
diagram.UpdateLayout();

// render the diagram to a bitmap
RenderTargetBitmap bmp = new RenderTargetBitmap((int)w, (int)h, 96, 96, PixelFormats.Default);
bmp.Render(diagram);

// set the source of your image to the bitmap
image.Source = bmp;
在示例中,如果PixelFormats.Default似乎不起作用,您可以尝试PixelFormats.Pbgra32,我认为这是一种更常见的格式,可用于此类应用

您也可以以类似的方式使用VisualBrush。我可以想象,从长远来看,您可能会为图表创建一个包装器类,以便仅在发生变化时(即图表的一部分或大小)自动显示图像副本并重新布局图表

  • 创建从Decorator继承的自定义类
  • 将图表控件包装在装饰器中
  • 重写MeasureOverride并简单地调用base.Measure,但在返回之前将结果存储在字段中
  • 添加允许您禁用度量调用的属性。如果该属性为true,只需返回MeasureOverride中以前的大小,而不是调用base.Measure
  • 更改视觉层次结构时设置属性
  • 从我的头脑中,我想不出为什么这不起作用


    不久前,我确实做了一些非常类似的事情。在中为侧面板实现滑动动画时,我使用了一个装饰器来防止内容在面板设置宽度动画时执行布局。我用最终的宽度计算了尺寸,存储了它,然后使用MeasureOverride来伪造当前的尺寸。。。这可以防止在尝试设置复杂控件宽度的动画时出现性能问题。:)

    另一种可能性是,当将内容从一个窗口移动到另一个窗口时,问题与其说与布局有关,不如说与视觉树的“断开”有关。这似乎会导致对依赖项属性进行大量的重新计算,如果内容的可视化树与我的一样,超过2000个控件,则速度非常慢

    我无法使用Actipro对接库本身找到一个优雅的解决方案,所以我想如何转移WPF的注意力,使其不做这种行为。我提出的解决方案是将我的内容创建为一个WinFormsHost控件和一个WinForms UserControl的子控件。然后,我将WinForms UserControl的内容设置为基于WPF的内容,该内容应显示为停靠窗口内容。我认为,当WPF开始从顶部遍历可视化树,在树被“剪断”时重新评估所有依赖属性时,它将运行到WinForms控件并停止


    我的Actipro停靠工具窗口通常需要6秒钟左右的时间来切换选项卡或浮动。现在它们基本上是瞬间的。您必须确保任何命令处理程序都不在应用程序级别,而是在WPF内容级别,并且您可能需要对某些样式文件的位置进行欺骗,但效果非常好。

    这个想法不错,然而,我已经注意到,使用RenderTargetBitmap拍摄中型图的快照可能需要几秒钟(我们使用它来自动生成错误报告)。该图也是交互式的,而不是静态的。我们有拖放。明白了,这两个都不适合你的情况。如果我想到别的,我会再发一次。祝你好运谢谢我需要这个。这听起来不可能实现我想要的,但你永远不知道是否有什么天才在那里。我们的应用程序几乎准备好了,这个问题是阻碍我们前进的最后一件事,我们只是找不到解决这个问题的方法。我们所有的测试版用户都在拖出图表停靠窗口,并思考“WTF?!应用程序崩溃了吗?”。不幸的是,对于这种情况,这不是正确的解决方案。图表被移动到一个新窗口中(我将停靠窗口设置为浮动窗口,因此停靠控件正在创建一个新窗口并将内容移动到其中)。如果我能投票支持你,我会的,因为答案仍然有用(我会一直记在心里,直到我遇到这种情况的那一天)。我不知道为什么它在这种情况下不起作用。如果你知道什么时候会发生这种情况,你可以设置标志,停靠库会把你的装饰器移到另一个地方。。。还是我遗漏了什么?在我看来,这只可能有很小的可能性。我只是无法想象,当从主窗口中删除某些内容并将其放入新窗口时,为其子窗口阻止布局处理的装饰程序会这样做。但是,我会尝试一下,因为我不知道内部渲染引擎到底做什么。我会让你知道这是否有效。