如何强制自定义FrameworkElement呈现更改的内容?

时间:2011-11-03 19:24:30

标签: c# wpf

我有一棵视觉树。主窗口有一个全尺寸的画布。 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渲染?非常感谢!

2 个答案:

答案 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();