本系列對實際項目中的XAML布局場景進行總結,給出了較優化的自適應布局解決方案,希望對大家有所幫助。
下面開始介紹局部布局設計模式。
1. 工具欄模式
適用於工具欄,標題等的布局。
此塊布局區域外層使用Grid,然后分為兩行或三行,標題或工具欄區域為Auto,主要內容區域為*。如果是標題,使用TextBlock,設置文字的字體和字號,還有Margin,把此行撐開。如果是工具欄,可放置一個橫向的StackPanel,右對齊,其中放置多個按鈕,通過設置按鈕的Content,Margin和Padding,把此行撐開。Content可以是文字,也可以是圖標或圖標加文字。
<Window x:Class="BlendDemo.DP1" 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" mc:Ignorable="d" Title="工具欄模式" Height="300" Width="400"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition/> </Grid.RowDefinitions> <Border Background="LightCyan"> <TextBlock Margin="5" Text="此處為標題" TextTrimming="WordEllipsis"/> </Border> <Grid Grid.Row="1" Background="AliceBlue"/> </Grid> </Window>
標題和工具欄可以在一行上,這時再放置一個Grid,把該行分為兩列,標題在左邊,其列為*,工具欄在右邊,其列為Auto,標題和工具欄的處理方式和前述方式類似,如果工具欄較高,標題設置為垂直居中對齊即可。
<Window x:Class="BlendDemo.DP1a" 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" mc:Ignorable="d" Title="工具欄模式" Height="300" Width="400"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <Grid Background="LightCyan"> <Grid.ColumnDefinitions> <ColumnDefinition /> <ColumnDefinition Width="Auto"/> </Grid.ColumnDefinitions> <TextBlock Margin="5" VerticalAlignment="Center" Text="此處為標題" TextTrimming="WordEllipsis"/> <StackPanel Grid.Column="1" Orientation="Horizontal" HorizontalAlignment="Right"> <Button Margin="0,5,5,5" Padding="15,5" Content=""/> <Button Margin="0,5,5,5" Padding="15,5" Content=""/> <Button Margin="0,5,5,5" Padding="15,5" Content=""/> </StackPanel> </Grid> <Grid Grid.Row="1" Background="AliceBlue"/> <StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Right"> <Button Margin="0,5,5,5" Padding="15,5" Content="按鈕1"/> <Button Margin="0,5,5,5" Padding="15,5" Content="按鈕2"/> <Button Margin="0,5,5,5" Padding="15,5" Content="按鈕3"/> </StackPanel> </Grid> </Window>
更復雜的情況,標題可能由多個部分組成,這時標題部分再由Grid分為多個列,前幾個列為Auto,最后一個為*,最后一個部分設置文字截斷。工具欄部分如果要實現按鈕大小相等的效果,可以使用Grid替代StackPanel,Grid設置多列為Auto,並設置 Grid.IsSharedSizeScope ="True",設置列寬時把SharedSizeGroup 設置為相同的字符串即可。這時再設置按鈕的Content,Margin和Padding,按鈕的大小都為由最大內容撐開的大小。
<Window x:Class="BlendDemo.DP1b" 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" mc:Ignorable="d" Title="工具欄模式" Height="300" Width="400"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <Grid Background="LightCyan"> <Grid.ColumnDefinitions> <ColumnDefinition /> <ColumnDefinition Width="Auto"/> </Grid.ColumnDefinitions> <Grid VerticalAlignment="Center"> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="Auto"/> <ColumnDefinition /> </Grid.ColumnDefinitions> <TextBlock Margin="5,5,0,5" Text="標題第1部分"/> <TextBlock Grid.Column="1" Margin="5,5,0,5" Text="-"/> <TextBlock Grid.Column="2" Margin="5,5,0,5" Text="標題第2部分" TextTrimming="WordEllipsis"/> </Grid> <StackPanel Grid.Column="1" Orientation="Horizontal" HorizontalAlignment="Right"> <Button Margin="0,5,5,5" Padding="15,5" Content=""/> <Button Margin="0,5,5,5" Padding="15,5" Content=""/> <Button Margin="0,5,5,5" Padding="15,5" Content=""/> </StackPanel> </Grid> <Grid Grid.Row="1" Background="AliceBlue"/> <Grid Grid.Row="2" HorizontalAlignment="Right" Grid.IsSharedSizeScope="True"> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" SharedSizeGroup="c1"/> <ColumnDefinition Width="Auto" SharedSizeGroup="c1"/> <ColumnDefinition Width="Auto" SharedSizeGroup="c1"/> </Grid.ColumnDefinitions> <Button Margin="0,5,5,5" Padding="15,5" Content="按鈕按鈕1"/> <Button Grid.Column="1" Margin="0,5,5,5" Padding="10,5" Content="按鈕2"/> <Button Grid.Column="2" Margin="0,5,5,5" Padding="10,5" Content="按鈕3"/> </Grid> </Grid> </Window>
2. 壓縮空白模式
一塊顯示區域較大,但顯示內容較少,這時可以把這塊區域使用Grid布局,顯示的區域使用Auto,剩余的空白區域使用多個不同比例的*分割。比如左側的查詢欄,兩塊查詢條件區和按鈕區是有效顯示區,這三塊區域使用Auto,四塊空白區域使用4*,4*, 4*, 3*分割,能夠達到較好的效果。按鈕區域又使用了這個模式,分為5列,按鈕部分為Auto,空白部分為2*,*, 2* ,中間的*還設置了最小寬15,這樣在一定范圍內能做到較好的自適應效果。
<Window x:Class="BlendDemo.DP2" 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" mc:Ignorable="d" Title="壓縮空白模式" Height="400" Width="600"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="*" MinWidth="165"/> <ColumnDefinition Width="3*"/> </Grid.ColumnDefinitions> <Border Background="LightCyan"> <Grid Margin="10,0"> <Grid.RowDefinitions> <RowDefinition Height="4*"/> <RowDefinition Height="Auto"/> <RowDefinition Height="4*"/> <RowDefinition Height="Auto"/> <RowDefinition Height="4*"/> <RowDefinition Height="Auto"/> <RowDefinition Height="3*"/> </Grid.RowDefinitions> <StackPanel Grid.Row="1"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <TextBlock Margin="5" VerticalAlignment="Center" Text="姓名:"/> <TextBox Grid.Column="1" Margin="0,5,5,5" Padding="2"/> </Grid> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <TextBlock Margin="5" VerticalAlignment="Center" Text="性別:"/> <ComboBox Grid.Column="1" Margin="0,5,5,5" Padding="2"/> </Grid> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <TextBlock Margin="5" VerticalAlignment="Center" Text="年齡:"/> <TextBox Grid.Column="1" Margin="0,5,5,5" Padding="2"/> </Grid> </StackPanel> <StackPanel Grid.Row="3"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <TextBlock Margin="5" VerticalAlignment="Center" Text="起始:"/> <DatePicker Grid.Column="1" Margin="0,5,5,5" Padding="2"/> </Grid> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <TextBlock Margin="5" VerticalAlignment="Center" Text="截至:"/> <DatePicker Grid.Column="1" Margin="0,5,5,5" Padding="2"/> </Grid> </StackPanel> <Grid Grid.Row="5"> <Grid.ColumnDefinitions> <ColumnDefinition Width="2*"/> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="*" MinWidth="15"/> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="2*"/> </Grid.ColumnDefinitions> <Button Grid.Column="1" Content="查詢" Padding="15,5"/> <Button Grid.Column="3" Content="清空" Padding="15,5"/> </Grid> </Grid> </Border> <Grid Grid.Column="1" Background="AliceBlue"/> </Grid> </Window>
3. 表單模式
如果要完成一個表單,可以使用Grid分為多行多列,行為Auto,列為Auto和*相間,其中標簽部分為Auto,填寫內容部分為*。每個部分都設置合適的字體字號,Margin和Padding,而不設置固定的大小,這樣就能完成一個自適應的表單。如果有的填寫內容長些,可以設置跨列為3,跨越兩個大的區域,或更大的數跨越更多的區域。
<Window x:Class="BlendDemo.DP3" 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" mc:Ignorable="d" Title="表單模式" Height="400" Width="600"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition/> </Grid.RowDefinitions> <Grid Background="LightCyan"> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="*"/> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="*"/> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <TextBlock Margin="5" VerticalAlignment="Center" Text="姓名:"/> <TextBox Margin="0,5" Grid.Column="1" Padding="2"/> <TextBlock Grid.Column="2" Margin="5" VerticalAlignment="Center" Text="性別:" TextTrimming="WordEllipsis"/> <ComboBox Grid.Column="3" Margin="0,5" Padding="2"/> <TextBlock Grid.Column="4" Margin="5" VerticalAlignment="Center" Text="年齡:" TextTrimming="WordEllipsis"/> <TextBox Grid.Column="5" Margin="0,5,5,5" Padding="2"/> <TextBlock Grid.Row="1" Margin="5" VerticalAlignment="Center" Text="電話:"/> <TextBox Grid.Row="1" Margin="0,5" Grid.Column="1" Padding="2"/> <TextBlock Grid.Column="2" Grid.Row="1" Margin="5" VerticalAlignment="Center" Text="地址:" TextTrimming="WordEllipsis"/> <TextBox Grid.Column="3" Grid.ColumnSpan="3" Grid.Row="1" Margin="0,5,5,5" Padding="2"/> </Grid> <Grid Grid.Row="1" Background="AliceBlue"/> </Grid> </Window>
4. 表格模式
可以使用下述Grid布局組合的方式顯示表格數據,但更好的方式是使用DataGrid控件。
首先,在最外層放一個ScrollViewer,設置水平滾動條可見性為Auto,垂直滾動條可見性為Disabled。其中放置一個Border用於顯示表格線。在其中放置一個Grid,分為2行,第0行為Auto,第1行為*。
然后,在外層Grid中第0行的位置上放置一個Grid,分為幾列,設置一定的寬度,每列中放置一個Border顯示表格線,Border中放一個TextBlock,顯示列標題,設置水平居中對齊,和合適的Margin。除了最后一列,還放置了GridSplitter,用於調節列的寬度。
最后,在外層Grid中第1行的位置上放置一個ScrollViewer,設置垂直滾動條可見性為Auto。其中放置一個ItemsControl,綁定到合適的數據,設置數據模板為Grid,分為和標題Grid一致的列數,使用SharedSizeGroup保證列的寬度和標題Grid的列的寬度一致。每列中放置一個Border顯示表格線,Border中放一個TextBlock,Text綁定到數據中對應的屬性上,設置水平居中對齊,和合適的Margin。
<Window x:Class="BlendDemo.DP4" 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" mc:Ignorable="d" Title="表格模式" Height="600" Width="800"> <Grid> <ScrollViewer Grid.Row="1" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Disabled"> <Border BorderBrush="Black" BorderThickness="0.5"> <Grid Grid.IsSharedSizeScope="True"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="200" SharedSizeGroup="c1"/> <ColumnDefinition Width="200" SharedSizeGroup="c2"/> <ColumnDefinition Width="200" SharedSizeGroup="c3"/> <ColumnDefinition Width="200" SharedSizeGroup="c4"/> <ColumnDefinition Width="200" SharedSizeGroup="c5"/> </Grid.ColumnDefinitions> <Border Grid.Column="0" BorderBrush="Black" BorderThickness="0.3"> <TextBlock Text="第1列" HorizontalAlignment="Center" Margin="5"/> </Border> <GridSplitter Grid.Column="0" Width="2" HorizontalAlignment="Right"/> <Border Grid.Column="1" BorderBrush="Black" BorderThickness="0.3"> <TextBlock Text="第2列" HorizontalAlignment="Center" Margin="5"/> </Border> <GridSplitter Grid.Column="1" Width="2" HorizontalAlignment="Right"/> <Border Grid.Column="2" BorderBrush="Black" BorderThickness="0.3"> <TextBlock Text="第3列" HorizontalAlignment="Center" Margin="5"/> </Border> <GridSplitter Grid.Column="2" Width="2" HorizontalAlignment="Right"/> <Border Grid.Column="3" BorderBrush="Black" BorderThickness="0.3"> <TextBlock Text="第4列" HorizontalAlignment="Center" Margin="5"/> </Border> <GridSplitter Grid.Column="3" Width="2" HorizontalAlignment="Right"/> <Border Grid.Column="4" BorderBrush="Black" BorderThickness="0.3"> <TextBlock Text="第5列" HorizontalAlignment="Center" Margin="5"/> </Border> </Grid> <ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto"> <ItemsControl ItemsSource="{Binding}"> <ItemsControl.ItemTemplate> <DataTemplate> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition SharedSizeGroup="c1"/> <ColumnDefinition SharedSizeGroup="c2"/> <ColumnDefinition SharedSizeGroup="c3"/> <ColumnDefinition SharedSizeGroup="c4"/> <ColumnDefinition SharedSizeGroup="c5"/> </Grid.ColumnDefinitions> <Border Grid.Column="0" BorderBrush="Black" BorderThickness="0.3"> <TextBlock Text="{Binding Column1}" HorizontalAlignment="Center" Margin="5"/> </Border> <Border Grid.Column="1" BorderBrush="Black" BorderThickness="0.3"> <TextBlock Text="{Binding Column2}" HorizontalAlignment="Center" Margin="5"/> </Border> <Border Grid.Column="2" BorderBrush="Black" BorderThickness="0.3"> <TextBlock Text="{Binding Column3}" HorizontalAlignment="Center" Margin="5"/> </Border> <Border Grid.Column="3" BorderBrush="Black" BorderThickness="0.3"> <TextBlock Text="{Binding Column4}" HorizontalAlignment="Center" Margin="5"/> </Border> <Border Grid.Column="4" BorderBrush="Black" BorderThickness="0.3"> <TextBlock Text="{Binding Column5}" HorizontalAlignment="Center" Margin="5"/> </Border> </Grid> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> </ScrollViewer> </Grid> </Border> </ScrollViewer> </Grid> </Window>
public class TableDataItem { public string Column1 { get; set; } public string Column2 { get; set; } public string Column3 { get; set; } public string Column4 { get; set; } public string Column5 { get; set; } } public partial class DP4 : Window { public DP4() { InitializeComponent(); var data = new List<TableDataItem>(); for (var i = 0; i < 30; i++) { data.Add(new TableDataItem { Column1 = "第1列數據", Column2 = "第2列數據", Column3 = "第3列數據", Column4 = "第4列數據", Column5 = "第5列數據" }); } DataContext = data; } }