2011-11-03 93 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強制渲染。

相關問題