前言
前段時(shí)間忙了一陣子Google Earth,這周又忙了一陣子架構師論文開(kāi)題報告,現在終于有時(shí)間繼續<WPF之路>了。先回憶一下上篇的內容,在《從HelloWorld到WPF World》中,我們對WPF有了個(gè)大概的了解,并了解了初學(xué)WPF時(shí)應該從哪些知識點(diǎn)入手。今天我們就從最基本的知識點(diǎn)之一布局系統來(lái)繼續學(xué)習WPF,主要包括如下內容。
這是一個(gè)很簡(jiǎn)單的問(wèn)題。簡(jiǎn)單來(lái)說(shuō),就是把一些控件有條理的擺放在界面上合適的位置,顯然擺的亂七八糟不能算布局。在WPF中,這個(gè)條理與WinForm中略有不同,讓我們看個(gè)很簡(jiǎn)單的界面:

這樣子的界面大家在熟悉不過(guò)了。依圖所示,WPF先用藍線(xiàn)(假設的線(xiàn))將界面劃分為上下兩部分,然后再有紅線(xiàn)劃分出多個(gè)方格,最后放入控件,其中每部分中的控件或劃分的空格只能縱向排列,或橫向排列,不能有其他選擇。大多數情況下,WPF程序界面上的控件都要按照此種遞歸的方法逐個(gè)排列,最終形成所看到的界面。
在上節中我們了解了WPF布局原理,這可以簡(jiǎn)單理解為大控件中按排或列放入小控件,小控件在按照同樣規則放入更小控件。這種能放入其他控件的控件是WPF布局系統中的基本元素——面板。面板是用來(lái)放東西的,既包括控件元素,也包括面板自己。面板不僅能承載其他子元素(控件),還能控制子元素的大小,位置以及如何排列。例如上述例子中,藍線(xiàn)劃分的面板控制子元素只能上下排列,而紅線(xiàn)劃分的面板控制的子元素只能橫向排列。
WPF默認提供了幾種面板都是從基面板(Panel)繼承而來(lái),看一下它們的繼承鏈。
System.Windows.Threading.DispatcherObject
System.Windows.DependencyObject
System.Windows.Media.Visual
System.Windows.UIElement
System.Windows.FrameworkElement
System.Windows.Controls.Control
System.Windows.Controls.Panel
System.Windows.Controls.Canvas
System.Windows.Controls.DockPanel
System.Windows.Controls.Grid
System.Windows.Controls.StackPanel
System.Windows.Controls.VirtualizingPanel
System.Windows.Controls.WrapPanel
WPF默認提供了數種布局控件,常用的包括如下幾種:
| 名稱(chēng) | 用法 | 說(shuō)明 |
| Canvas | ![]() | 此面板可承載任意元素,包括控件,圖形,甚至文字。各種元素依據屏幕坐標確定位置。 |
| DockPanel | ![]() | 此面板可指定元素的排列??糠绞?,每個(gè)子元素的排列方式可以不同。 |
| Grid | ![]() | 此面板使子元素按照縱橫網(wǎng)格排列。 |
| StackPanel | ![]() | 此面板使子元素按照水平或垂直方向排列,兩個(gè)方向只能選其一。 |
VirtualizingStackPanel | ![]() | 與StackPanel相同,不同之處在于它可以使內容虛擬化。 |
| WrapPanel | ![]() | 使子元素按照水平或垂直方向排列,在行或列處換行或列,依舊按照水平或垂直方向從左到右或從上到下排列。 |
3,測量與排列
當我們在面板上放入子元素,并設置相應的屬性時(shí),WPF的布局系統自動(dòng)為我們完成2個(gè)過(guò)程:測量和排列,這是兩個(gè)非常重要的過(guò)程。
由于WPF界面元素有很多與布局有關(guān)的屬性,如坐標,大小,對齊方式,相對位置,間距等。首先這些屬性使用的是與設備無(wú)關(guān)的分辨率單元,這導致同樣大小的元素在不同界面上顯示的效果可能不同;其次每個(gè)屬性值有一定的優(yōu)先級,例如Button的Height和Width屬性?xún)?yōu)先于Stretch屬性,如果設置 Height, Width 以及 Stretch,會(huì )導致 Stretch被忽略。
因此,盡管在設計時(shí)指定了屬性值,布局系統依然需要重新計算每個(gè)子元素在界面上的實(shí)際大小,位置,邊距等值,這些值被稱(chēng)為“FinalSize”。
4,基本屬性:Alignment,Margin和Pading
在設計UI時(shí),WPF為我們提供了一些屬性用于精確定位元素,其中最常用的有三個(gè):Alignment(包括水平,垂直),Margin,Pading,具體用法如下:
| 名稱(chēng) | 說(shuō)明 |
| Alignment | 子元素在水平(垂直)方向的對齊方式,有左對齊,右對齊(頂端對齊,底部對齊),中間對齊,拉伸填充等四種方式。 |
| Margin | 用于指定元素與其子級或同級之間的距離,包括上下左右四個(gè)值。也可通過(guò)使用 Margin="20" 同時(shí)指定四個(gè)值。 |
| Pading | Padding 在大多數方面類(lèi)似于 Margin,只有少數元素有(公開(kāi)),用于將子元素的有效大小增大指定的厚度。 |
通過(guò)上面我們了解到子元素通過(guò)一些屬性值的設置實(shí)現在面板上布局,比如Alignment對齊屬性,Dock??颗帕袑傩?。這些屬性不屬于子元素本身,而依賴(lài)與所在的父元素。比如同樣是Button,在DockPanel中有Dock屬性,而在Grid中就沒(méi)有。這些屬性的存在依賴(lài)與父元素,在WPF中稱(chēng)做“附加屬性”。
附加屬性的用途是允許不同的子元素為實(shí)際在父元素中定義的屬性指定唯一值,目的是讓子元素通知父元素它將如何在界面中呈現。如上面提到的DockPanel.Dock 屬性,因為它將在 DockPanel 中包含的元素上設置,而不是在 DockPanel 本身設置。注意,相對于子元素,父元素提供的附加屬性相當于全局屬性。
通過(guò)上面我們了解到,當給界面元素的布局屬性賦值時(shí),布局系統需要重新計算和排列所有子元素的“FinalSize”(因為改變影響不可知)。這是一個(gè)遞歸的過(guò)程。如果不注意,可能會(huì )帶來(lái)性能問(wèn)題。因此在設計時(shí)應注意下面幾點(diǎn):
1,應注意哪些屬性值更改會(huì )引起執行布局系統的遞歸更新;
2,如有可能,應使用 RenderTransform 而不要使用 LayoutTransform;
3,避免不必要地調用 UpdateLayout,因為UpdateLayout強制調用布局系統的遞歸更新;
4,當包含大量元素集合時(shí),請使用 VirtualizingStackPanel虛擬化元素;
通過(guò)本文,我們大概了解了WPF的布局系統,常用的布局面板,與布局有關(guān)的幾個(gè)屬性,以及設計開(kāi)發(fā)UI時(shí)的注意事項。這些內容很多與WinForm中的相關(guān)概念相通,可以說(shuō)是舊瓶裝新酒,稍加思考,并不難理解;如果深入了解,會(huì )發(fā)現與WinForm截然不同。但作為初學(xué)者,如果能靈活使用文中所講的知識點(diǎn),深入理解注意點(diǎn),對自身的提高還是很有幫助的。
聯(lián)系客服