這部分的內容來(lái)自于即將出版的新書(shū)《WPF Unleashed》的第三章樣章。關(guān)于什么是邏輯樹(shù),我們先看下面的一個(gè)偽XAML代碼的例子:
<Window ......>
<StackPanel>
<Label>LabelText</Lable>
</StackPanel>
</Window>
在這樣一個(gè)簡(jiǎn)單UI中,Window是一個(gè)根結點(diǎn),它有一個(gè)子結點(diǎn)StackPanel。而StackPanel有一個(gè)子結點(diǎn)Label。注意Label下還有一個(gè)子結點(diǎn)string(LabelText),它同時(shí)也是一個(gè)葉子結點(diǎn)。這就構成了窗口的一個(gè)邏輯樹(shù)。邏輯樹(shù)始終存在于WPF的UI中,不管UI是用XAML編寫(xiě)還是用代碼編寫(xiě)。WPF的每個(gè)方面(屬性、事件、資源等等)都是依賴(lài)于邏輯樹(shù)的。
視覺(jué)樹(shù)基本上是邏輯樹(shù)的一種擴展。邏輯樹(shù)的每個(gè)結點(diǎn)都被分解為它們的核心視覺(jué)組件。邏輯樹(shù)的結點(diǎn)對我們而言基本是一個(gè)黑盒。而視覺(jué)樹(shù)不同,它暴露了視覺(jué)的實(shí)現細節。下面是Visual Tree結構就表示了上面四行XAML代碼的視覺(jué)樹(shù)結構:
并不是所有的邏輯樹(shù)結點(diǎn)都可以擴展為視覺(jué)樹(shù)結點(diǎn)。只有從System.Windows.Media.Visual和System.Windows.Media.Visual3D繼承的元素才能被視覺(jué)樹(shù)包含。其他的元素不能包含是因為它們本身沒(méi)有自己的提交(Rendering)行為。
在Windows Vista SDK Tools當中的XamlPad提供查看Visual Tree的功能。需要注意的是XamlPad目前只能查看以Page為根元素,并且去掉了SizeToContent屬性的XAML文檔。如下圖所示:
注意圖中工具欄特別標記的地方。我們可以看到Visual Tree確實(shí)比較復雜,其中還包含有很多的不可見(jiàn)元素,比如ContentPresenter。Visual Tree雖然復雜,但是在一般情況下,我們不需要過(guò)多地關(guān)注它。我們在從根本上改變控件的風(fēng)格、外觀(guān)時(shí),需要注意Visual Tree的使用,因為在這種情況下我們通常會(huì )改變控件的視覺(jué)邏輯。
WPF中還提供了遍歷邏輯樹(shù)和視覺(jué)樹(shù)的輔助類(lèi):System.Windows.LogicalTreeHelper和System.Windows.Media.VisualTreeHelper。注意遍歷的位置,邏輯樹(shù)可以在類(lèi)的構造函數中遍歷。但是,視覺(jué)樹(shù)必須在經(jīng)過(guò)至少一次的布局后才能形成。所以它不能在構造函數遍歷。通常是在OnContentRendered進(jìn)行,這個(gè)函數為在布局發(fā)生后被調用。
其實(shí)每個(gè)Tree結點(diǎn)元素本身也包含了遍歷的方法。比如,Visual類(lèi)包含了三個(gè)保護成員方法VisualParent、VisualChildrenCount、GetVisualChild。通過(guò)它們可以訪(fǎng)問(wèn)Visual的父元素和子元素。而對于FrameworkElement,它通常定義了一個(gè)公共的Parent屬性表示其邏輯父元素。特定的FrameworkElement子類(lèi)用不同的方式暴露了它的邏輯子元素。比如部分子元素是Children Collection,有是有時(shí)Content屬性,Content屬性強制元素只能有一個(gè)邏輯子元素。
本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請
點(diǎn)擊舉報。