一文搞懂WPF布局

文章目录

TabControl

TabControl即选项卡,通过TabStripPlacement可以调整选项卡的标题的位置;其内部则由一个个不同的TabItem构成,每个TabItem通过Header来声明标题。

例如

<TabControl TabStripPlacement ="Left">
    <TabItem Header="布局学习" >
        
    </TabItem>
</TabControl>

一文搞懂WPF布局

在主界面的布局学习选项卡中添加

<TabControl>
  <TabItem Header="TabControl">
      <TabControl TabStripPlacement="Bottom">
          <TabItem Header="Bottom"/>
      </TabControl>
  </TabItem>

  <TabItem Header="Grid">
  </TabItem>

  <TabItem Header="Canvas">
  </TabItem>

  <TabItem Header="WrapPanel">
  </TabItem>

  <TabItem Header="DockPanel">
  </TabItem>

  <TabItem Header="StackPanel">
  </TabItem>

  <TabItem Header="TabPanel">
  </TabItem>
</TabControl>

一文搞懂WPF布局

UniformGird

顾名思义,Grid即网格,UniformGrid即处处相同的网格,只能定义行数和列数,而每行每列的尺寸是不能定义的。

例如在Uniform选项卡下添加一个两行两列的UniformGrid:

<UniformGrid Columns="2" Rows="2">
    <Button Background="red" Margin="10"/>
    <Button Background="green" Margin="10"/>
    <Button Background="blue" Margin="10"/>
    <Button Background="Yellow" Margin="10"/>
</UniformGrid>

一文搞懂WPF布局

Gird

相比之下,Grid则是一个比较高级的网格,可以自行定义行列的尺寸。但高级的同时也意味着繁琐,其内部的控件必须声明所在的行列。

在声明网格尺寸时,如果添加*,则表示按照比例。

<TabItem Header="Grid">
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="150"/>
        <ColumnDefinition Width="250"/>
        <ColumnDefinition Width="400"/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="1*"/>
        <RowDefinition Height="2*"/>
        <RowDefinition Height="3*"/>
    </Grid.RowDefinitions>
    <Button Grid.Column="0" Grid.Row="0" Content="00" Margin="10"/>
    <Button Grid.Column="0" Grid.Row="1" Content="01" Margin="10"/>
    <Button Grid.Column="0" Grid.Row="2" Content="02" Margin="10"/>
    <Button Grid.Column="1" Grid.Row="0" Content="10" Margin="10"/>
    <Button Grid.Column="1" Grid.Row="1" Content="11" Margin="10"/>
    <Button Grid.Column="1" Grid.Row="2" Content="12" Margin="10"/>
    <Button Grid.Column="2" Grid.Row="0" Content="20" Margin="10"/>
    <Button Grid.Column="2" Grid.Row="1" Content="21" Margin="10"/>
    <Button Grid.Column="2" Grid.Row="2" Content="22" Margin="10"/>
</Grid>
</TabItem>

一文搞懂WPF布局

Canvas

传统的绝对布局,通过Left, Top, Bottom, Right来确定控件的位置。

<Canvas>
    <Button Canvas.Left="10" Canvas.Top="20" Content="L10,T20" />
    <Button Canvas.Left="100" Canvas.Bottom="200" Content="L100,B200" />
    <Button Canvas.Right="250" Canvas.Top="50" Content="R250,T50" />
    <Button Canvas.Left="450" Canvas.Top="30" Content="450,30" />
</Canvas>

一文搞懂WPF布局

WrapPanel

可以换行的顺序布局模式。

<WrapPanel>
    <Button Height="30" Width="100" Margin="10"/>
    <Button Height="30" Width="100" Margin="10"/>
    <Button Height="30" Width="100" Margin="10"/>
    <Button Height="30" Width="100" Margin="10"/>
    <Button Height="30" Width="100" Margin="10"/>
    <Button Height="30" Width="100" Margin="10"/>
    <Button Height="30" Width="100" Margin="10"/>
</WrapPanel>

一文搞懂WPF布局

DockPanel

DockPanel是十分灵活的布局模式,可以理解为按照指示填充剩余空间。

<DockPanel>
    <Button DockPanel.Dock="Left" Content="Left" Margin="10"/>
    <Button DockPanel.Dock="Top" Content="Top" Margin="10"/>
    <Button DockPanel.Dock="Right" Content="right" Margin="10"/>
    <Button DockPanel.Dock="Bottom" Content="Bottom" Margin="10"/>
    <Button Content="Last" Margin="10"/>
</DockPanel>

一文搞懂WPF布局

如图所示,我们首先填充的是一个靠左的内容为Left的按钮,则这个Left填充了全部的左面的内容;然后是一个靠上的内容为Top的按钮,这个按钮填充了剩余空间的上部分。

DockPanel控件默认LastChildFillTrue,即最后一个控件填充剩余的所有空间,所以最后的那个last按钮才会这么大。

stackPanel

可以理解为不能换行的WrapPanel或者分布不均匀的UniformGrid。通过Orientation可以调整方向。

<StackPanel Orientation="Vertical">
    <StackPanel Orientation="Horizontal">
        <Button Content="btn1" Width="200" Margin="10"/>
        <Button Content="btn2" Width="300" Margin="10"/>
        <Button Content="btn3" Width="400" Margin="10"/>
    </StackPanel>
    <Button Content="btn5" Margin="10"/>
    <Button Content="btn6" Margin="10"/>
</StackPanel>

一文搞懂WPF布局

布局相关

TabPanel

其实就是TabControl的标题栏,根据前面案例的一些经验,可以猜测默认的TabPanel有点类似于WrapPanel,毕竟可以回车。

那么有没有办法让其变成均匀的分布,就像UniformGrid一样?方法就是把TabPanel的风格换成UniformGrid。

<TabItem Header="tabPanel">
   <TabItem.Resources>
       <Style TargetType="{x:Type TabControl}">
           <Setter Property="Template">
               <Setter.Value>
                   <ControlTemplate TargetType="{x:Type TabControl}">
                       <Grid>
                           <Grid.RowDefinitions>
                               <RowDefinition Height="Auto"/>
                               <RowDefinition Height="*"/>
                           </Grid.RowDefinitions>
                           <UniformGrid x:Name="HeaderPanel" Rows="1" 
                                    IsItemsHost="True" KeyboardNavigation.TabIndex="1" Panel.ZIndex="1"/>
                       </Grid>
                   </ControlTemplate>
               </Setter.Value>
           </Setter>
       </Style>
   </TabItem.Resources>
   <TabControl>
       <TabItem Header="tab1"/>
       <TabItem Header="tab2" />
       <TabItem Header="tab3" />
       <TabItem Header="tab4" />
       <TabItem Header="tab5" />
   </TabControl>
</TabItem>

通过修改模板,就能够达到如下效果

一文搞懂WPF布局

virtualizingPanel

顾名思义,即虚拟化模板,对窗口外部的信息进行虚化,从而提高布局过程中的性能。为了实现这一点,也必须同ScrollViewer共同使用。

<TabItem Header="VirtualizingPanel ">
   <ScrollViewer>
       <StackPanel>
           <Button Content="btnLoad" Width="60" Height="20" Click="btnLoad_Click"/>
           <ListBox MinWidth="600" VirtualizingStackPanel.IsVirtualizing="False"  x:Name="lbData"
              ItemsSource="{Binding XPath=Team}"/>
       </StackPanel>
   </ScrollViewer>
</TabItem>

为了测试其性能,我们在后台添加10000个按钮试一下。

private void btnLoad_Click(object sender, RoutedEventArgs e)
{
   for (int i = 0; i < 10000; ++i)
       lbData.Items.Add(new Button { Width=60,Height=20,Content=i.ToString()});
}
上一篇:C# WinForm 修改TableControl标签


下一篇:WPF基础五:UI③带标题内容控件TabControl