#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

Advertisement

#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

#889 – Scrolling a ScrollViewer from Code

You can programmatically cause a ScrollViewer’s content to scroll by using one or more of the ScrollViewer’s methods listed below.

To scroll content vertically:

  • Call LineUp to scroll up one line
  • Call LineDown to scroll down one line
  • Call PageUp to scroll up one page
  • Call PageDown to scroll down one page
  • Call ScrollToHome to scroll to the top
  • Call ScrollToEnd to scroll to the bottom

To scroll horizontally, use the corresponding methods LineLeftLineRightPageLeft, PageRight, ScrollToLeftEnd and ScrollToRightEnd.

        <StackPanel Orientation="Horizontal">
            <Button Content="Up 1" Click="btnUpOne_Click"/>
            <Button Content="Down 1" Click="btnDownOne_Click"/>
        </StackPanel>
        <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 Source="Nero.jpg" Height="100" Margin="5"/>
                <Image Source="Galba.jpg" Height="100" Margin="5"/>
            </StackPanel>
        </ScrollViewer>

 

        private void btnUpOne_Click(object sender, RoutedEventArgs e)
        {
            svMain.LineUp();
        }

        private void btnDownOne_Click(object sender, RoutedEventArgs e)
        {
            svMain.LineDown();
        }

889-001

#888 – Different Ways to Scroll Content in a ScrollViewer

There are several different ways that you can scroll content within a ScrollViewer.

To scroll content vertically:

  • Click and drag the vertical scrollbar with the mouse
  • Click the up/down arrow widgets at either end of the scrollbar  (scroll small amount)
  • Tab through control that can receive focus.  When you tab to a control, it is scrolled into view.
  • Use the mouse scroll wheel
  • Press up / down arrow keys  (scroll small amount)
  • Press Page Up Page Down keys  (scroll by full page)
  • Ctrl-Home to scroll to beginning, Ctrl-End to scroll to end

To scroll content horizontally:

  • Click and drag the horizontal scrollbar with the mouse
  • Click the up/down arrow widgets at either end of the scrollbar  (scroll small amount)
  • Tab through control that can receive focus.  When you tab to a control, it is scrolled into view.
  • Press left / right arrow keys  (scroll small amount)

#887 – The Difference between Disabled and Hidden Scrollbar Visibility

ScrollViewer allows setting the horizontal or vertical scrollbar visibility to AutoDisabledHidden or Visible.  The Disabled and Hidden options are similiar, but subtly different.

  • Hidden – Scrollbar is not shown, but content is allowed to scroll (e.g. using arrow keys).  Content in ScrollViewer is given an infinite amount of space in the scrolling direction.  (E.g. Infinite width if HorizontalScrollBarVisibility is set to Hidden).
  • Disabled – Content cannot scroll and is not allowed to be larger than the ScrollViewer’s size in the scrolling direction.

We can see how this works by placing a horizontally-oriented WrapPanel inside a ScrollViewer.  When the HorizontalScrollBarVisibility is set to Hidden, the WrapPanel is infinitely wide and therefore never wraps.  (You can still scroll the content using the arrow keys).

887-001

If the HorizontalScrollBarVisibility is set to Disabled, the WrapPanel can’t scroll horizontally and its width is constrained to the width of the ScrollViewer, causing it to wrap.

887-002