WPF布局原則—不應顯示設定大小
為了控件的大小可以自适應容器,控件不應該顯示設定寬高。比如這裡的
<Grid></Grid>
标簽就沒有設定寬高(為了友善觀察,設定了灰色的背景),當我們拖大拖小視窗時,可以看到grid元素也是跟随視窗變化而變化
<Window x:Class="ControlExercise.Window2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ControlExercise"
mc:Ignorable="d"
Title="Window2" Height="450" Width="800">
<Grid Background="Gray">
</Grid>
</Window>
反之,如果我們設定了寬高,不管怎麼拖動視窗,Grid都是固定大小的。
<Grid Width="100" Height="100" Background="Gray">
</Grid>
布局容器之Grid
Grid控件為WPF中最重要的布局容器
- 通過
來定義行,Grid.RowDefinitions
來定義列Grid.ColumnDefinitions
以下代碼定義了兩行,兩列,是以Grid被分割成了四個部分
<Grid>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
</Grid>
- Grid定義寬度高度的三種方式
- 指定數值:(不建議)
Width=50
2)等比例設定:
<ColumnDefinition Width="1*"></ColumnDefinition> <ColumnDefinition Width="2*"></ColumnDefinition> <ColumnDefinition Width="3*"></ColumnDefinition>
3)自适應 :
Width="Auto"
該單元格适應内部控件大小
- 元素的跨行或跨列安放
-
GridSplitter 控件就是用來分割Grid控件的,必須放在Grid裡面
GridSplitter的作用是可以讓使用者拖動來改變grid行或列的寬度或高度,使用起來非常簡單,把它加到Grid裡的某一行或者某一列,再配置設定合适的空間如5個像素這樣就可以了
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock FontSize="55" HorizontalAlignment="Center" VerticalAlignment="Center" TextWrapping="Wrap">Left side</TextBlock>
<GridSplitter Grid.Column="1" Width="5" HorizontalAlignment="Stretch" />
<TextBlock Grid.Column="2" FontSize="55" HorizontalAlignment="Center" VerticalAlignment="Center" TextWrapping="Wrap">Right side</TextBlock>
- 共享尺寸組
SharedSizeGroup屬性允許相同名的元素具有等大的效果
<!--定義一個父容器,Grid.IsSharedSizeScope="True"是必須的-->
<Grid ShowGridLines="True" Grid.IsSharedSizeScope="True">
<!--在父容器中定義了兩行-->
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<!--在父容器的第一行定義一個子容器-->
<Grid ShowGridLines="True" Name="grid_1" Background="blue" Grid.Row="0">
<Grid.ColumnDefinitions>
<!--第一個子容器的第一列指定了SharedSizeGroup屬性-->
<ColumnDefinition Width="50" SharedSizeGroup="A" ></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
</Grid>
<!--在父容器的第二行定義一個子容器-->
<Grid ShowGridLines="True" Name="grid_2" Background="Green" Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<!--第二個子容器的第二列指定了SharedSizeGroup屬性-->
<ColumnDefinition SharedSizeGroup="A" ></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
</Grid>
</Grid>
布局容器之StackPanel控件
堆棧面闆:在單行或單列中放置子元素
在視窗中放
<StackPanel></StackPanel>
标簽,stackPanel中放置3個button,1個Label,效果如下;可以看出,StackPanel預設會将子元素垂直排列
可以通過Orientation屬性來控制子元素排列方向
Orientation="Horizontal"
表示水準排列
Orientation="Vertical"
表示垂直排列,它是預設的
Margin
屬性為元素添加外邊距
Margin="10,15,20,25"的四個值分别表示左、上、右、下的位置,如下圖
MinWidth
屬性可以控制元素的最小尺寸,也就是說該元素不可以小于設定的最小寬度值
MaxWidth
屬性可以控制元素的最大尺寸,也就是說該元素不可以大于設定的最大寬度值
布局容器之WrapPanel控件
WrapPanel容器将子元素按行或列一個接一個進行排列,如果一行或一列放不下,元素會被擠到下一行或一列;同一行元素的高度一樣(水準排列),同一列元素的寬度是一樣的(豎直排列)
<WrapPanel>
<Button Content="Button" />
<Button Content="Button" />
<!--這裡隻設定了一個button的高度,與它同一行的元素都變成了一樣的高度-->
<Button Content="Button" Height="50" />
<Button Content="Button" />
<Button Content="Button" />
<Button Content="Button" />
<Button Content="Button" />
<Button Content="Button" />
</WrapPanel>
布局容器之DockPanel控件
DockPanel支援讓元素簡單地停靠在整個面闆的某一條邊上,然後拉伸元素以填滿全部寬度或高度。它也支援讓一個元素填充其他已停靠元素沒有占用的剩餘空間
DockPanel有一個Dock附加屬性,是以子元素用4個值來控制她們的停靠:Left、Top、Right、Bottom。Dock 沒有Fill值。作為替代,最後的子元素将加入一個DockPanel并填滿所有剩餘的空間,除非DockPanel的LastChildFill屬性為false,它将朝某個方向停靠
<DockPanel>
<Button Content="Button"/>
<Button Content="Button"/>
<Button Content="Button"/>
<Button Content="Button"/>
<Button Content="Button"/>
</DockPanel>
預設情況下,元素會依次橫向排列,并填充整個空間
<DockPanel>
<!--DockPanel.Dock屬性可控制元素在DockPanle中依靠的位置-->
<Button Content="Button" DockPanel.Dock="Top" />
<Button Content="Button" DockPanel.Dock="Bottom"/>
<Button Content="Button" DockPanel.Dock="Left"/>
<Button Content="Button" DockPanel.Dock="Right"/>
<Button Content="Button"/>
</DockPanel>
布局容器之Canvas面闆
Canvas面闆是基于坐标的布局容器;Canvas中的子元素的位置是需要顯性設定的固定位置,通過Canvas的屬性Left/Rigth/Top/Bottom來設定子元素相對位置
下例是一個距離下邊界20、左邊界20位置的一個按鈕
<Canvas>
<Button Canvas.Bottom="20" Canvas.Left="20">Hello</Button>
</Canvas>
下例中定義了三個圖形,一個圓,三個矩形,它們之間的重疊是按預設的順序疊加的(未定義過Z坐标的,其Z坐标是0),可以通過設定Canvas.ZIndex屬性值或Panel.ZIndex來調整元素的重疊順序,值越大的越靠前
<Canvas>
<Ellipse Fill="Gainsboro" Canvas.Left="25" Canvas.Top="25" Width="200" Height="200" />
<Rectangle Canvas.ZIndex="3" Fill="LightBlue" Canvas.Left="25" Canvas.Top="25" Width="50" Height="50" />
<Rectangle Panel.ZIndex="2" Fill="LightCoral" Canvas.Left="50" Canvas.Top="50" Width="50" Height="50" />
<Rectangle Panel.ZIndex="1" Fill="LightCyan" Canvas.Left="75" Canvas.Top="75" Width="50" Height="50" />
</Canvas>
當然也可以調整Z軸順序,效果如下
布局容器之InkCavas
InkCavas是一個畫圖控件,它允許在它之上加載其它控件,比如加載一個按鈕;可以通過InkCanvas的Right/Left/Bottom/Top屬性來指定元素的位置
<InkCanvas>
<Button Content="Hello" InkCanvas.Bottom="50" InkCanvas.Left="30" />
</InkCanvas>
運作程式後,可發現,當滑鼠移動到InkCanvas區域時,滑鼠會變成一個黑點,按下滑鼠左鍵移動會畫出線條
InkCanvas
的
EditingMode
的屬性可根據不同的值,設定圖畫的不同功能
EditingMode="EraseByPoint"
表示滑鼠變成一個可擦除點的工具
EditingMode="EraseByStroke"
表示滑鼠變成一個可橡皮擦
EditingMode="GestureOnly"
表示按下滑鼠可畫線,滑鼠松開後所畫的線條将消失
EditingMode="Ink"
表示按下滑鼠可畫出墨線,本屬性值是預設的
EditingMode="InkAndGesture"
與Ink功能類似,但同時可以識别使用者的手勢
EditingMode="None"
表示沒有任何反應
EditingMode="Select"
表示可以選擇一個元素,可以移動它、删除它,改變形狀等
下面通過将這些屬性動态的加載到下拉框中,通過選擇不同的屬性值來體驗不同的畫圖效果
其中我感覺Select很有用,基于此可以實作讓客戶拖動縮放控件的效果。關鍵是不需要任何代碼,運作狀态控件的選中,拖動,縮放都已經實作了,非常友善
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<InkCanvas Grid.Row="1" Name="incas">
<Button Content="Hello" InkCanvas.Bottom="50" InkCanvas.Left="30" />
</InkCanvas>
<ComboBox Grid.Row="0" Name="cmb_model" SelectionChanged="cmb_model_SelectionChanged" />
</Grid>