咱們首先來了解一下圖形化用戶界面(Graphic User Interface)也就是咱們經常聽到的GUI。舉個簡單的例子,一樣是數據,咱們能夠用控制檯程序加格式控制符等輸出,可是這些都不如GUI來的友好和方便。html
WPF相對於其它只能使用編程語言進行UI設計,具備專門用於UI設計的XAML,而且可以確保界面佈局能恰倒好處的適應不一樣的窗口尺寸。編程
咱們來查看Window和Page的源碼,發現Window的間接基類ContentControl和Page類都使用了一個object類型的Content屬性。因此它只能包含一個元素,可是咱們想放置多個元素怎麼辦呢?這個時候咱們就須要使用佈局容器。編程語言
爲何佈局容器又能夠添加多個元素呢?全部的WPF佈局容器都派生自System.Windows.Controls.Panel這個抽象類。咱們從類層次結構圖中就不難發現它所包含的一系列佈局容器。咱們再來看看這個Panel類的源代碼,就會發現該類有一個ContentProperty("Children")特性,因此咱們會在該類中找到一個UIElementCollection類型(該類實現了IList接口)的Children屬性。只要是繼承自UIElement的類,均可以添加到佈局容器中。佈局
下面讓咱們來看看其中的一些佈局容器以及與之相關聯的控件屬性。post
StackPanelurl
它是最簡單的佈局容器,容許子元素在單行或者單列以堆棧的形式放置。spa
<StackPanel Orientation="Vertical" Background="LightCyan"> <Label Background="LemonChiffon">A Button Stack</Label> <Button>Button A</Button> <Button>Button B</Button> <Button>Button C</Button> </StackPanel>
咱們運行會發現,StackPanel容器會充滿整個窗口,由於它的HorizontalAlignment、VerticalAlignment屬性值都是Stretch。設計
子元素是按照自上而下的方式排列的,由於咱們設置了Orientation屬性(默認值就是Vertical,因此這裏咱們能夠不設置該屬性);若是設置成Horizontal,就會從左到右排列。在默認狀況下,每一個子元素的高度都適合與它們本身內容的高度。若是是Horizontal,每一個子元素的寬度都適合它們本身內容的長度。code
咱們拉伸運行的WPF程序,會發現StackPanel始終會充滿整個窗口,子元素也會根據設置作相應的變化。orm
咱們能夠設置子元素的一些屬性配合佈局容器的屬性,來決定佈局。常見的屬性有:HorizontalAlignment、VerticalAlignment、Margin、MinWidth、MinHeight、MaxWidth、MaxHeight、Height、Width。
<Window x:Class="WPFDemo.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Width="200" Height="350"> <StackPanel Background="LightCyan"> <Label Background="LemonChiffon">A Button Stack</Label> <Button HorizontalAlignment="Left">Button A</Button> <Button HorizontalAlignment="Center">Button B</Button> <Button HorizontalAlignment="Right">Button C</Button> <Button Margin="5" Height="40" Width="100" HorizontalAlignment="Right">Button D</Button> <Button MinWidth="320">Button E</Button> </StackPanel> </Window>
運行這個程序,咱們就會發現A、B、C三個Button分別位於水平方向上的不一樣位置;Button D距離四周的元素有5個單位的距離,而且指定了該按鈕的高度和寬度;Button E指定了MinWidth,遠大於Window的200,因此剛運行的時候左邊被截斷,須要咱們經過拉伸纔可徹底看見。
Grid
顧名思義,Grid會以網格的形式對內容元素們進行佈局。它具備以下的特色:
· 能夠經過RowDefinitions和ColumnDefinitions屬性,它們分別是RowDefinition和ColumnDefinition集合。定義任意多的行和列。
· 行的高度,列的寬度可使用絕對數值(double數值加單位後綴px、in、cm、pt,不過在設置的時候最好不要加單位),比例值(double數值後加一個*號),自動值(字符串Auto)來靈活設置。
· 內部元素可使用Grid的附加屬性Grid.Row、Grid.Column、Grid.RowSpan、Grid.ColumnSpan設置本身所在的行、列、縱向跨幾行、橫向跨幾列。
· 能夠設置子元素的對齊方向。
<Grid VerticalAlignment="Top" HorizontalAlignment="Left" ShowGridLines="True" Width="250" Height="100"> <Grid.ColumnDefinitions> <ColumnDefinition /> <ColumnDefinition /> <ColumnDefinition /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="*" /> <RowDefinition Height="1.5*"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <TextBlock FontSize="20" FontWeight="Bold" Grid.ColumnSpan="3" Grid.Row="0">2013 Products Shipped</TextBlock> <TextBlock FontSize="12" FontWeight="Bold" Grid.Row="1" Grid.Column="0" HorizontalAlignment="Center">Quarter 1</TextBlock> <TextBlock FontSize="12" FontWeight="Bold" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Center">Quarter 2</TextBlock> <TextBlock FontSize="12" FontWeight="Bold" Grid.Row="1" Grid.Column="2" HorizontalAlignment="Center">Quarter 3</TextBlock> <TextBlock Grid.Row="2" Grid.Column="0" VerticalAlignment="Center">50000</TextBlock> <TextBlock Grid.Row="2" Grid.Column="1" VerticalAlignment="Center">100000</TextBlock> <TextBlock Grid.Row="2" Grid.Column="2" VerticalAlignment="Center">150000</TextBlock> <TextBlock FontSize="16" FontWeight="Bold" Grid.ColumnSpan="3" Grid.Row="3">Total Units: 300000</TextBlock> </Grid>
在這個示例中,咱們還設置了ShowGridLines屬性,它會生成虛線的邊框。咱們能夠修改該邊框,具體能夠查看陳希章老師的這篇文章:爲WPF和Silverlight的Grid添加邊框。
咱們還可使用UseLayoutRounding屬性來控制佈局舍入。
咱們還可使用GridSplitter來拖動分割窗口。
<Grid> <Grid.RowDefinitions> <RowDefinition></RowDefinition> <RowDefinition></RowDefinition> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="200"></ColumnDefinition> <ColumnDefinition Width="Auto"></ColumnDefinition> <ColumnDefinition Width="200"></ColumnDefinition> </Grid.ColumnDefinitions> <Button>1</Button> <Button Grid.Column="2">2</Button> <Button Grid.Row="2">3</Button> <Button Grid.Column="2" Grid.Row="2">4</Button> <GridSplitter Grid.Column="1" Grid.Row="0" Grid.RowSpan="3" Width="2" VerticalAlignment="Stretch" HorizontalAlignment="Center" ShowsPreview="True"></GridSplitter> </Grid>
這是一個左右拖動的分割窗口,因此咱們把GridSplitter豎立放置鋪滿(VerticalAlignment="Stretch"),並跨行(Grid.RowSpan="3"),還要設置它的寬度Width(這樣纔可見);最後還要設置列的寬度爲自動值Auto。咱們還看到ShowsPreview屬性爲True,這個是當咱們拖動分割條時,會有一個會射的陰影跟隨鼠標運行,以顯示預覽。同理,我能夠設置上下拖動的分割線,這裏就不過多敘述了。
還有一個比較有意思的是SharedSizeGroup特性。
<Grid Margin="3"> <StackPanel> <StackPanel Grid.IsSharedSizeScope="True"> <Grid Grid.Row="0" Margin="3" Background="LightYellow" ShowGridLines="True"> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" SharedSizeGroup="TextLabel"></ColumnDefinition> <ColumnDefinition Width="Auto"></ColumnDefinition> <ColumnDefinition></ColumnDefinition> </Grid.ColumnDefinitions> <Label Margin="5">A very long bit of text</Label> <Label Grid.Column="1" Margin="5">More text</Label> <TextBox Grid.Column="2" Margin="5">A text box</TextBox> </Grid> <Label Grid.Row="1" >Some text in between the two grids...</Label> <Grid Grid.Row="2" Margin="3" Background="LightYellow" ShowGridLines="True"> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" SharedSizeGroup="TextLabel"></ColumnDefinition> <ColumnDefinition></ColumnDefinition> </Grid.ColumnDefinitions> <Label Margin="5">Short</Label> <TextBox Grid.Column="1" Margin="5">A text box</TextBox> </Grid> </StackPanel> </StackPanel> </Grid>
咱們能夠設置須要共享尺寸的列ColumnDefinition或者行RowDefinition的SharedSizeGroup屬性,把他們都設置成同一個值;而後再把Grid的IsSharedSizeScope附加屬性設置到父容器上,並設置爲True。(本例嵌套了2個StackPanel就是爲了說明IsSharedSizeScope的設置方式,其實徹底沒有必要嵌套2個StackPanel,直接就能夠設置在Grid上)
還有一個更簡單的網格佈局容器,UniformGrid,它能夠直接設置Rows、Columns屬性,設置行列數;它沒有Rows、Columns這些附加屬性,是按照子元素的添加的順序由左到右,由上到下排列的。
Canvas
直譯就是畫布的意思。它一般用於一些設計基本不會再有改動的小型佈局。
Canvas佈局容器是最輕量級的佈局容器,它沒有包含負責的佈局邏輯,以改變其子元素的首選尺寸。
咱們能夠設置Canvas.Left、Canvas.Top(或者Canvas.Right、Canvas.Buttom)附加屬性來定位子元素的位置。
<Canvas> <Button Canvas.Left="10" Canvas.Top="10">(10,10)</Button> <Button Canvas.Left="120" Canvas.Top="30">(120,30)</Button> <Button Canvas.Left="60" Canvas.Top="80" Width="50" Height="50" Canvas.ZIndex="1">(60,80)</Button> <Button Canvas.Left="70" Canvas.Top="120" Width="100" Height="50">(70,120)</Button> <Button Canvas.Left="80" Canvas.Top="150" Width="100" Height="50">(60,80)</Button> </Canvas>
默認狀況下,全部子元素的都具備相同的ZIndex屬性值0;若是子元素的ZIndex值相同,就按照他們在Canvas中添加的前後順序進行顯示。因此上一個示例中,最後一個Button會顯示在倒數第二個Button上面;第三個由於咱們顯示設置了ZIndex的值爲1,大於默認值0,因此第三個在第四個上面。
這一節咱們講了3個很是具備表明性的佈局容器,固然須要作好佈局是一件很是困難的事情,須要考慮全面。因此還須要咱們真正動手作的時候,不斷的積累經驗。這裏只是一個簡單的介紹佈局容器。下一節,咱們會來介紹一下WPF的控件。