2011-11-03 62 views
2

我有一个视觉树。主窗口有一个全尺寸的帆布。 Canvas拥有一些自定义视觉效果的根。第一个自定义视觉(A)可以根据用户正在查看的内容(儿童(Bs,DrawingVisuals))进行扩展和缩小。当主窗口调整大小时,我想添加子项或从A中删除子项。当用户在视图中滚动任何方向时可能会发生同样的情况。当添加儿童(Bs)时,我希望他们被渲染。 (被删除的B是没有问题的,因为它们不再可见。)如何强制自定义FrameworkElement呈现更改的内容?

以一个场景:主窗口为640x480。我调整到两倍的大小,这将揭示更多的Bs,然后将它们添加到A.到目前为止,我无法获得新添加的Bs来渲染,即使使用FrameworkElement的Invalidate ???()方法。我在主窗口中尝试了Invalidate ???(),并在添加了Bs时尝试了A。 (我没有与Bs,认为他们是新的。)看起来像Invalidate ???()不是要走的路。

我发现了一个黑客,它允许新的Bs在调整大小时呈现。在主窗口中,我可以从Canvas中删除A并将其添加回来,这会强制树被重新渲染:

this.contentCanvas.Children.RemoveRange(0,contentCanvas.Children.Count); //删除根 this.contentCanvas.Children.Add(this.CustomVisual_A); // readd root

由于显而易见的原因,这是不可取的,特别是当滚动时。具体来说,正在添加和删除的Bs以这种方式进行管理,因为它们非常大,我需要尽可能减少内存占用并提高渲染速度。这就是为什么我会遇到麻烦。

有人可以帮助我了解我需要做些什么才能让新添加的Bs呈现?非常感谢!

回答

0

这有几个电话......

 element.UpdateLayout(); 
     element.InvalidateArrange(); 
     element.InvalidateMeasure(); 
     element.InvalidateVisual(); 
+0

谢谢。是的,我试图使用所有这些(由上面的Invalidate ???()表示)。我也试过UpdateLayout()。缺少的关键部分在我的答案中找到。 – Vaughn

3

我解决了这个。尽管FrameworkElement的是定制的,您需要使用标准AddVisualChild()RemoveVisualChild()的方法来管理你的孩子:

this.AddVisualChild(new B()); 
... 
this.RemoveVisualChild(existingB); 

你仍然坚持自己的B的集合,但似乎除非你使用AddVisualChild()RemoveVisualChild()底层FrameworkElement没有看到变化(实际上Panel,Canvas的超类)。

这也可能涉及父母以某种方式通知;不确定。最终,这些收集管理方法会导致在Panel上定义的OnVisualChildrenChanged()方法被调用,所以它应该在A中实现。当时我向/从内部集合中添加/删除子项,然后调用base:

protected override void OnVisualChildrenChanged(DependencyObject added, DependencyObject removed) 
{ 
    if (added != null) 
    { 
     this.children.Add((B) added); 
    } 

    if (removed != null) 
    { 
     this.children.Remove((B) removed); 
    } 

    base.OnVisualChildrenChanged(added, removed); 
} 

这会引起一些内部指示,表明必须进行渲染。

我觉得这种情况必须发生,因为从我的自定义画布中删除A并重新添加A强制渲染。

相关问题