Understand WPF layout in one article

TabControl

TabControl is a tab. You can adjust the position of the title of the tab through TabStripPlacement; Its interior is composed of different tabitems, and each TabItem declares the title through the Header.

for example

<TabControl TabStripPlacement ="Left">
    <TabItem Header="Layout learning" >
        
    </TabItem>
</TabControl>

Add in the layout learning tab of the main interface

<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>

UniformGird

As the name suggests, Grid is a Grid, and UniformGrid is a Grid that is the same everywhere. Only the number of rows and columns can be defined, but the size of each row and column cannot be defined.

For example, add a UniformGrid with two rows and two columns under the Uniform tab:

<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>

Gird

In contrast, Grid is an advanced Grid, which can define the size of rows and columns by itself. But advanced also means cumbersome, and its internal controls must declare the row and column.

When declaring the mesh size, if you add *, it means to scale.

<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>

Canvas

In the traditional absolute layout, the position of the control is determined by left, top, bottom and 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>

WrapPanel

Sequential layout mode that can wrap lines.

<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>

DockPanel

DockPanel is a very flexible layout mode, which can be understood as filling the remaining space according to the instructions.

<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>

As shown in the figure, we first fill in a Left button, and then the Left fills in all the contents on the Left; Then there is a Top button, which fills the upper part of the remaining space.

The DockPanel control defaults to True LastChildFill, that is, the last control fills all the remaining space, so the last button is so large.

stackPanel

It can be understood as WrapPanel that cannot wrap lines or UniformGrid with uneven distribution. Orientation allows you to adjust the 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>

Layout related

TabPanel

In fact, it is the title bar of TabControl. According to some experience of the previous cases, you can guess that the default TabPanel is a little similar to WrapPanel. After all, you can enter.

So is there any way to make it evenly distributed, just like UniformGrid? The method is to change the style of TabPanel to 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>

By modifying the template, the following effects can be achieved

virtualizingPanel

As the name suggests, the virtualization template virtualizes the information outside the window, so as to improve the performance in the layout process. To achieve this, it must also be used with 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>

To test its performance, we added 10000 buttons in the background to try.

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()});
}

Tags: C# WPF UI

Posted on Sat, 20 Nov 2021 06:29:21 -0500 by Malcerous