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