WPF布局工作內部原理
WPF布局容器的繼承機制WPF渲染布局時主要執行了兩個工作:測量和排列測量階段,容器遍歷所有子元素,並詢問子元素所期望的尺寸排列階段,容器在合適的位置放置子元素,並設置元素的最終尺寸這是一個遞歸的過程,界面中任何一個容器元素都會被遍歷到
![]()
DispatcherObjectDependencyObjectWPF應用程序使用單線程親和模型(STA:Single-Thread Affinity),這意味着整個用戶界面都為單個線程擁有,同時也意味着從另一個線程與用戶界面元素交互是不安全的,但有很多情況下需要從其他線程訪問界面元素,那怎么辦呢?WPF有一個統一的機制來處理這些問題,這個我們在后續的章節涉及到之后再深入講解,大家只要知道,只要繼承DispatcherObject的界面元素就能很方便的處理這些問題就好啦
WPF的屬性的實現機制和Winform程序有很大的差異,Winform控件的屬性很多是通過繼承機制得來的,在你認為超過90%的用戶界面控件的屬性通常留其初始值時,為每一個屬性存儲一個字段將是對內存的巨大的浪費。 DependencyObject(依賴屬性)解決了僅僅存儲改變了屬性的問題。默認值在依賴屬性中只存儲一次。這只是依賴項屬性的一個好處,還有其他好處我們以后再聊。VisualUIElementWPF程序中的所有可視化元素基本上都是繼承自Visual類,這個類封裝了繪圖指令和附加的繪圖細節(比如透明和裁剪等),如果你不想用WPF的界面元素,更希望使用一個輕量級的繪圖API,那么你可以直接對Visual對象進行編程
UIElement為可視元素增加了更多的功能,比如布局、輸入、焦點、事件、命令等,FrameworkElement
對UIElement進行了增強,比如UIElement為布局機制設置了基礎,但FrameworkElement提供了支持它的重要屬性,如:HorizontalAlignment、Margin等屬性Panel是所有布局元素的基類,所有布局元素都派生自此類型,它用於放置和排列WPF元素,這個抽象類只包含三個公共屬性:Background、Children、IsItemHost( IsItemHost標志着控件是不是類似TreeView、ListView這樣的控件)
布局屬性
布局容器內的子元素對自身的大小、位置有一定的決定權
子元素可以設置自身的布局屬性來調整自己的位置和大小
HorizontalAlignment 水平對齊方式 VerticalAlignment 垂直對其方式 Margin 在元素周圍添加一定的空隙 MinWidth/MinHeight 最小尺寸 MaxWidth/MaxHeight 最大尺寸Width/Height 尺寸屬性
Grid行與列的尺寸
如果要顯式的設置Grid的行和列的尺寸,只要設置具體的值即可:<RowDefinition Height="30"></RowDefinition>但很多時候需要讓行或者列自適應高度或者寬度,那么可以給相應的屬性設置Auto值:<RowDefinition Height="Auto"></RowDefinition>還有的時候需要按比例設置行和列的高度或者寬度,那么可以使用*通配符:
<RowDefinition Height="*"></RowDefinition><RowDefinition Height="2*"></RowDefinition>
Grid跨行與跨列
當希望Grid內的元素跨越多行或者多列的時候,可以使用RowSpan或ColumnSpan來實現<Button Grid.RowSpan="2" Grid.ColumnSpan="2"></Button>
GridSpliter分割窗口
經常有這樣的需求,需要通過拖動的方式改變一個窗口內部區域的大小GridSpliter能很好的滿足這種需求,在增加一行或一列的大小的同時,減小其他行或者列的大小(因為一個窗口的區域大小是固定的,此消彼長)注意HorizontalAlignment屬性必須設置
![]()
![]()
![]()
![]()
共享尺寸
假設我們有兩個Grid,每個Grid都有兩行,而且兩行的高度都設置為auto,我們希望這兩個Grid的行高保持一致也就是說某一個grid的行高根據自身的內容變化之后,另一個grid的行高也跟着變化以往實現這樣的需求,一定要編寫C#代碼才行,現在我們可以使用WPF的共享尺寸特性來實現這一需求(大家可以看到,第二個grid里的button我沒有設置高度,但它也變高了)
![]()
均衡表格UniformGrid
當你不希望使用Grid復雜的行列設置,只希望把元素“平均”放置到界面上,那么你可以使用UniformGrid來實現這樣的需求
Z軸順序
我們知道在Canvas布局容器中,如果位置重疊,后設置的元素會蓋住先設置的元素,如果想打破這種規定,那么可以使用ZIndex屬性:
修改記錄
2014-12-26:編寫前兩部分內容2014-12-29:修改第二節的內容,增加最后兩節的內容2014-12-30:完成剩余的內容2015-01-05:修改了幾個文字
參考資料
《Pro WPF 4.5 in C# 4th Edition》