#896 – A TabControl Groups Content into a Series of Pages

You can use a TabControl to organize content in your application into a series of pages, allowing the user to click on the page that contains the content that they want to see.

The TabControl contains a series of TabItem elements representing each tab.  Each TabItem has a Header property defining text or content to appear on the clickable part of the tab.  Each TabItem also has a single child element, representing the content to be displayed when you are viewing the tab.  This will normally be a panel that contains other controls.

    <TabControl Margin="10">
        <TabItem Header="You">
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto"/>
                    <ColumnDefinition/>
                </Grid.ColumnDefinitions>

                <Label Content="Name:"/>
                <TextBox Grid.Column="1" Width="120" Margin="5"
                         HorizontalAlignment="Left"/>
                <Label Grid.Row="1" Content="Age:"/>
                <TextBox Grid.Row="1" Grid.Column="1" Width="80" Margin="5"
                         HorizontalAlignment="Left"/>
            </Grid>
        </TabItem>

        <TabItem Header="Zappa">
            <StackPanel>
                <Image Source="Zappa.jpg" Height="80" Margin="5"/>
                <Label Content="Composer and musician"
                       HorizontalAlignment="Center"/>
            </StackPanel>
        </TabItem>
    </TabControl>

896-001
896-002

#895 – Adding a Watermark to a GroupBox

Here’s an example of changing a GroupBox so that the Header element becomes a rotated watermark.

To do this, you modify the default template for the GroupBox.  We change the ContentPresenter for the header to appear in the middle of the parent Grid and we rotate it.

        <Style x:Key="GroupBoxStyle1" TargetType="{x:Type GroupBox}">
            <Setter Property="BorderBrush" Value="#D5DFE5"/>
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type GroupBox}">
                        <Grid SnapsToDevicePixels="true">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="6"/>
                                <ColumnDefinition Width="*"/>
                                <ColumnDefinition Width="6"/>
                            </Grid.ColumnDefinitions>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="Auto"/>
                                <RowDefinition Height="Auto"/>
                                <RowDefinition Height="*"/>
                                <RowDefinition Height="6"/>
                            </Grid.RowDefinitions>
                            <Border BorderBrush="Transparent" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Grid.ColumnSpan="3" Grid.Column="0" CornerRadius="4" Grid.Row="1" Grid.RowSpan="3"/>
                            <ContentPresenter Grid.Column="1" Margin="{TemplateBinding Padding}" Grid.Row="2" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                            <ContentPresenter ContentSource="Header" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                                              Grid.Row="1" Grid.RowSpan="2" Grid.Column="1"
                                              HorizontalAlignment="Center" VerticalAlignment="Center"
                                              RenderTransformOrigin="0.5,0.5">
                                <ContentPresenter.RenderTransform>
                                    <RotateTransform Angle="45"/>
                                </ContentPresenter.RenderTransform>
                            </ContentPresenter>
                            <Border BorderBrush="White" BorderThickness="{TemplateBinding BorderThickness}" Grid.ColumnSpan="3" CornerRadius="4" Grid.Row="1" Grid.RowSpan="3">
                                <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="3">
                                    <Border BorderBrush="White" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="2"/>
                                </Border>
                            </Border>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

Below, we use the new style in a GroupBox and specify a header to use for the watermark.

    <GroupBox Margin="10" Style="{DynamicResource GroupBoxStyle1}">
        <GroupBox.Header>
            <Label Content="Roman Guys" FontSize="36"
                   Opacity="0.3" Foreground="MediumBlue"/>
        </GroupBox.Header>
        <StackPanel>
          <!-- Content here -->
        </StackPanel>
    </GroupBox>

895-001

#894 – Creating a GroupBox with a Header But No Border

There are cases where you might want a GroupBox for grouping a set of child controls, but without the visual border around the controls.  You can retain the header element, but remove the border of a GrouBox by setting the BorderBrush property to Transparent.

    <GroupBox Margin="10" Header="Roman Guys" BorderBrush="Transparent">
        <StackPanel>
            <StackPanel Orientation="Horizontal">
                <Image Source="Augustus.jpg" Height="100" Margin="5"/>
                <TextBlock Text="Augustus" VerticalAlignment="Center"/>
            </StackPanel>
            <StackPanel Orientation="Horizontal">
                <Image Source="Tiberius.jpg" Height="100" Margin="5"/>
                <TextBlock Text="Tiberius" VerticalAlignment="Center"/>
            </StackPanel>
            <StackPanel Orientation="Horizontal">
                <Image Source="Caligula.jpeg" Height="100" Margin="5"/>
                <TextBlock Text="Caligula" VerticalAlignment="Center"/>
            </StackPanel>
        </StackPanel>
    </GroupBox>

894-001

#893 – Creating a GroupBox with a Border But No Header

There are cases where you might want a GroupBox for grouping a set of child controls, but without the associated header text.  If you try just omitting the Header, but you’ll see a little gap at the top of the GroupBox.

893-001

To remove the gap you could just use a Border element instead of a GroupBox, changing its style to match the GroupBox.  You can also edit the default style of the GroupBox.

To edit the style of the GroupBox, start by right-clicking the GroupBox control in Visual Studio and select Edit TemplateEdit a Copy.

893-002

Accept the default name for the style.

893-003

Within the Style element, find the OpacityMask, near the bottom, and comment it out.

894-004

Note that your GroupBox element is now using your modified copy of the style.

    <GroupBox Margin="10" BorderBrush="DarkGray"
              Style="{DynamicResource GroupBoxStyle1}">

The GroupBox will no longer have the little gap where the header should go.
893-005

#892 – Changing the Font for Everything within a GroupBox

If you want to change the font used for both the header of a GroupBox, as well as any textual elements within it, you can set font-related properties on the GroupBox itself.

In the example below, the GroupBox on the left does not set font properties:

<GroupBox Header="Roman Dudes" Margin="10">

The GroupBox on the right sets both FontSize and FontFamily:

        <GroupBox Header="Greek Dudes" Margin="10"
                  FontSize="16" FontFamily="Comic Sans MS">

The GroupBox on the right then uses the specified font for both the header and for any Label elements within its boundaries.
892-001

#891 – Changing the Border of a GroupBox

You can easily change the border drawn around a GroupBox control by setting its BorderThickness and BorderBrush properties.

<GroupBox Header="Roman Dudes" Margin="10"
          BorderThickness="2" BorderBrush="Purple">
    <StackPanel>
        <StackPanel Orientation="Horizontal">
            <Image Source="Augustus.jpg" Height="100" Margin="5"/>
            <TextBlock Text="Augustus" VerticalAlignment="Center"/>
        </StackPanel>
        <StackPanel Orientation="Horizontal">
            <Image Source="Tiberius.jpg" Height="100" Margin="5"/>
            <TextBlock Text="Tiberius" VerticalAlignment="Center"/>
        </StackPanel>
        <StackPanel Orientation="Horizontal">
            <Image Source="Caligula.jpeg" Height="100" Margin="5"/>
            <TextBlock Text="Caligula" VerticalAlignment="Center"/>
        </StackPanel>
    </GroupBox>

891-001

#890 – Bringing a Control into View within a ScrollViewer

If you have a particular control contained within a ScrollViewer and you want to programmatically scroll to that control, you can use its BringIntoView method.

For example, when we click the “Find Nero” in the sample below, we’ll scroll the image of Nero into view.

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition/>
        </Grid.RowDefinitions>

        <Button Content="Find Nero" Click="btnFindNero_Click"
                HorizontalAlignment="Center" Margin="5"
                Padding="10,5"/>
        <ScrollViewer Grid.Row="1" Name="svMain" VerticalScrollBarVisibility="Visible">
            <StackPanel>
                <Image Source="Augustus.jpg" Height="100" Margin="5"/>
                <Image Source="Tiberius.jpg" Height="100" Margin="5"/>
                <Image Source="Caligula.jpeg" Height="100" Margin="5"/>
                <Image Source="Claudius.jpg" Height="100" Margin="5"/>
                <Image Name="imgNero" Source="Nero.jpg" Height="100" Margin="5"
                       ToolTip="Yup, I'm Nero"/>
                <Image Source="Galba.jpg" Height="100" Margin="5"/>
            </StackPanel>
        </ScrollViewer>
    </Grid>
        private void btnFindNero_Click(object sender, RoutedEventArgs e)
        {
            imgNero.BringIntoView();
        }

890-001