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

本文关键字:自定义 何强制 FrameworkElement | 更新日期: 2023-09-27 18:13:16

我有一个视觉树。主窗口有一个全尺寸的Canvas。Canvas保存了一些自定义视觉效果的根。第一个自定义Visual (A)可以根据用户正在查看的内容展开和收缩,这些内容属于子元素(b,即DrawingVisuals)。当主窗口调整大小时,我想在a中添加或删除子窗口。当用户在视图中滚动任何方向时,也可能发生相同的情况。当添加子节点(b)时,我希望渲染它们。(删除的b没有问题,因为它们无论如何都不再可见。)

假设一个场景:主窗口是640x480。我将大小调整为该大小的两倍,这将显示更多的b,然后将它们添加到a中。到目前为止,我无法获得新添加的b来渲染,即使使用FrameworkElement的Invalidate??()方法也是如此。()在主窗口和添加b时在A中。(我没有使用b,因为它们是新出现的。)看来Invalidate??()不是正确的方法。

我发现了一个hack,允许新的b渲染调整大小。在主窗口中,我可以从画布中删除A并将其添加回去,这将强制重新渲染树:

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

显然,这是不可取的,尤其是在滚动时。具体来说,正在添加和删除的b以这种方式进行管理,因为它们非常大,我需要尽可能地减少内存占用并提高渲染速度。这就是为什么我不怕麻烦。

有人能帮助我了解我需要做什么来获得新添加的b渲染?谢谢!

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

我解决了这个问题。即使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强制渲染。

有几个调用…

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