我有一棵视觉树。主窗口有一个全尺寸的画布。 Canvas拥有一些自定义Visual的根。第一个自定义Visual(A)可以根据用户正在查看的内容进行扩展和收缩,这些内容位于子级(Bs,即DrawingVisuals)中。当主窗口调整大小时,我想向A添加子项或从A中删除子项。当用户在视图中滚动任何方向时,可能会发生同样的情况。当添加子(Bs)时,我希望它们被渲染。 (被删除的Bs没有问题,因为它们不再可见。)
拍摄场景:主窗口为640x480。我调整大小两倍,这将显示更多的Bs,然后将其添加到A.到目前为止,我无法获得新添加的Bs渲染,即使使用FrameworkElement的Invalidate ???()方法也是如此。我在主窗口和A中添加了Bs时尝试了Invalidate ???()。 (我没有Bs,认为它们是新的。)似乎Invalidate ???()不是要走的路。
我发现了一个允许新B在调整大小时渲染的黑客攻击。在主窗口中,我可以从Canvas中删除A并将其添加回来,这会强制树被重新渲染:
this.contentCanvas.Children.RemoveRange(0,contentCanvas.Children.Count); //删除root this.contentCanvas.Children.Add(this.CustomVisual_A); //读根
由于显而易见的原因,这是不可取的,尤其是在滚动时。具体来说,正在添加和删除的Bs以这种方式进行管理,因为它们非常大,我需要尽可能减少内存占用并提高渲染速度。这就是我遇到麻烦的原因。
有人可以帮助我了解我需要做些什么才能让新添加的B渲染?非常感谢!
答案 0 :(得分:3)
我解决了这个问题。即使FrameworkElement是自定义的,您也需要使用标准AddVisualChild()
和RemoveVisualChild()
方法来管理您的孩子:
this.AddVisualChild(new B());
...
this.RemoveVisualChild(existingB);
您仍然维护自己的B集合,但似乎除非您使用AddVisualChild()
和RemoveVisualChild()
,否则底层FrameworkElement
看不到更改(实际上是Panel,超类)画布)。
这也可能涉及父母以某种方式通知;不确定。最终这些集合管理方法会导致在Panel上定义的OnVisualChildrenChanged()
方法被调用,因此它应该在A中实现。那时我在子集中添加/删除子集,然后调用在基地:
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);
}
这会导致一些内部迹象表明渲染是必要的。
我认为必须发生这样的事情,因为从我的自定义Canvas中删除A并重新添加A强制渲染。
答案 1 :(得分:0)
有几个要求......
element.UpdateLayout();
element.InvalidateArrange();
element.InvalidateMeasure();
element.InvalidateVisual();