#911 – Use ItemTemplate to Control Content on Tabs

You can use the ItemContainerStyle of a TabControl to dictate the content that appears on the tabs, creating a style that sets each TabItem’s HeaderTemplate.

As a slightly more straightforward way to do the same thing, you can just set the TabControl’s ItemTemplate property to a DataTemplate that defines the content for each tab.

        <TabControl Margin="5"
                    ItemsSource="{Binding RomanDudes}">
            <!-- Change ItemTemplate to control content on tabs -->
            <TabControl.ItemTemplate>
                <DataTemplate>
                    <StackPanel>
                        <Image Source="{Binding Image}" Height="50"/>
                        <TextBlock Text="{Binding Name}" HorizontalAlignment="Center"/>
                    </StackPanel>
                </DataTemplate>
            </TabControl.ItemTemplate>
            <!-- Change ContentTemplate to control main content -->
            <TabControl.ContentTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal" VerticalAlignment="Top"
                                Margin="10">
                        <Image Source="{Binding Image}" Height="80"/>
                        <StackPanel Margin="10">
                            <TextBlock Text="{Binding Name}"/>
                            <TextBlock Text="{Binding ReignStart}"/>
                            <TextBlock Text="{Binding ReignEnd}"/>
                            <TextBlock Text="{Binding KnownFor}"/>
                        </StackPanel>
                    </StackPanel>
                </DataTemplate>
            </TabControl.ContentTemplate>
        </TabControl>

911-001

Advertisement

#910 – Using Data Binding to Control the Currently Selected Tab of a TabControl

In addition to using data binding to control the tabs that appear in a TabControl, you can use binding to control which tab is currently selected.

Below, we bind the SelectedIndex of a TabControl to a property in our class.  We do the same for a ComboBox, as well as binding the ItemSource of the ComboBox to the same collection that the TabControl is bound to.  After doing this, we can use the ComboBox to select the correct tab or manually select a different tab to cause the ComboBox to be updated.

        <TabControl Margin="5"
                    ItemsSource="{Binding RomanDudes}"
                    SelectedIndex="{Binding DudeIndex}">
        <!-- Templates here -->
        </TabControl>

 

        <ComboBox Grid.Row="1" HorizontalAlignment="Center" Margin="0,5"
                  ItemsSource="{Binding RomanDudes}"
                  SelectedIndex="{Binding DudeIndex}"/>

Property that we bind to:

        private int dudeIndex;
        public int DudeIndex
        {
            get { return dudeIndex; }
            set
            {
                if (value != dudeIndex)
                {
                    dudeIndex = value;
                    RaisePropertyChanged("DudeIndex");
                }
            }
        }

910-001

#909 – Binding a TabControl to a List of Objects, part III

You can bind a TabControl to a list of objects, which causes a new TabItem to be created for each element in the list.

By default, both the header and the content of each TabItem is set to the result of invoking ToString on each item in the collection.  You can set the Header of each tab by setting a HeaderTemplate.

You set the Content of each TabItem by setting the ContentTemplate property of the TabControl to a DataTemplate containing the desired items.

    <TabControl Margin="5"
                ItemsSource="{Binding RomanDudes}">
        <TabControl.ItemContainerStyle>
            <Style TargetType="TabItem">
                <Setter Property="HeaderTemplate">
                    <Setter.Value>
                        <DataTemplate>
                            <StackPanel>
                                <Image Source="{Binding Image}" Height="50"/>
                                <TextBlock Text="{Binding Name}" HorizontalAlignment="Center"/>
                            </StackPanel>
                        </DataTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </TabControl.ItemContainerStyle>
        <TabControl.ContentTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal" VerticalAlignment="Top"
                            Margin="10">
                    <Image Source="{Binding Image}" Height="80"/>
                    <StackPanel Margin="10">
                        <TextBlock Text="{Binding Name}"/>
                        <TextBlock Text="{Binding ReignStart}"/>
                        <TextBlock Text="{Binding ReignEnd}"/>
                        <TextBlock Text="{Binding KnownFor}"/>
                    </StackPanel>
                </StackPanel>
            </DataTemplate>
        </TabControl.ContentTemplate>
    </TabControl>

909-001

#908 – Binding a TabControl to a List of Objects, part II

To bind a TabControl to a list of objects, you can set the ItemsSource of the TabControl to an ObservableCollection of the desired object type.  This will cause a new TabItem to be created for each element in the collection.

By default, both the header and the content of each TabItem is set to the result of invoking ToString on each item in the collection.  To set the Header of each tab, dictating what appears on the tab itself, you can set the ItemContainerStyle of the TabControl to a style element, where you set the HeaderTemplate, as shown below.

<TabControl Margin="5"
            ItemsSource="{Binding RomanDudes}">
    <TabControl.ItemContainerStyle>
        <Style TargetType="TabItem">
            <Setter Property="HeaderTemplate">
                <Setter.Value>
                    <DataTemplate>
                        <StackPanel>
                            <Image Source="{Binding Image}" Height="50"/>
                            <TextBlock Text="{Binding Name}" HorizontalAlignment="Center"/>
                        </StackPanel>
                    </DataTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </TabControl.ItemContainerStyle>
</TabControl>

In the next post, we’ll set the content of each TabItem as well.
908-001

 

Note: For a cleaner way to do this, see: Use ItemTemplate to Control Content on Tabs

#907 – Binding a TabControl to a List of Objects, part I

Instead of explicitly defining each tab of a TabControl in XAML, you can bind the TabControl to a list of objects, each tab representing an object in the list.

Suppose that we have a collection of Emperor objects, as follows:

public MainWindow()
{
this.InitializeComponent();
this.DataContext = this;

romanDudes = new ObservableCollection&lt;Emperor&gt;();
romanDudes.Add(new Emperor("Augustus", "27 BC", "14 AD", "Found bricks, left marble",
new Uri("Augustus.jpg", UriKind.Relative)));
// Add more dudes here
RaisePropertyChanged("RomanDudes");
}

private ObservableCollection&lt;Emperor&gt; romanDudes;
public ObservableCollection&lt;Emperor&gt; RomanDudes
{
get { return romanDudes; }
}

// INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged = delegate { };

private void RaisePropertyChanged(string propName)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}

We set the ItemsSource of the TabControl to the list:

&lt;TabControl Margin="5"
ItemsSource="{Binding RomanDudes}"/&gt;

The TabControl now creates a tab for each Emperor object.
907-001
Both the Header and the Content for each TabItem defaults to the object’s string representation–the emperor’s name, in this case).

#906 – Programmatically Changing the Current Tab on a TabControl

You can change the currently selected tab on a TabControl in one of several ways:

  • Change the TabControl’s SelectedIndex property (0..n-1)
  • Change the TabControl’s SelectedItem property (if you have a reference to the TabItem for the tab that you want to switch to)
  • Use data binding and change the object that the SelectedItem is bound to

Below is an example of changing the SelectedIndex property when the user clicks on a Button.

        <TabControl Name="tabMeals">
            <TabItem Header="Breakfast">
                <StackPanel>
                    <RadioButton Content="Eggs"/>
                    <RadioButton Content="Cereal"/>
                    <RadioButton Content="Spam"/>
                </StackPanel>
            </TabItem>
            <TabItem Header="Lunch">
                <StackPanel>
                    <RadioButton Content="Ham Sandwich"/>
                    <RadioButton Content="Soup"/>
                    <RadioButton Content="Wimpy Burger"/>
                </StackPanel>
            </TabItem>
            <TabItem Header="Dinner">
                <StackPanel>
                    <RadioButton Content="Spam Sandwich"/>
                    <RadioButton Content="Spam Casserole"/>
                    <RadioButton Content="Spam Jello Surprise"/>
                </StackPanel>
            </TabItem>
        </TabControl>
        <Button Grid.Row="1" Content="Change Tabs" HorizontalAlignment="Center" Padding="10,5"
                Click="Button_Click"/>

 

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            if (tabMeals.SelectedIndex == (tabMeals.Items.Count - 1))
                tabMeals.SelectedIndex = 0;
            else
                tabMeals.SelectedIndex++;
        }

906-001

#905 – Executing Some Code when a User Changes Tabs on a TabControl

You can execute some code whenever a user changes tabs on a TabControl by handling the TabControl’s SelectionChanged event.  Below we have a TabControl and we define a handler for its SelectionChanged event.

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

        <TabControl SelectionChanged="TabControl_SelectionChanged">
            <TabItem Header="Breakfast">
                <StackPanel>
                    <RadioButton Content="Eggs"/>
                    <RadioButton Content="Cereal"/>
                    <RadioButton Content="Spam"/>
                </StackPanel>
            </TabItem>
            <TabItem Header="Lunch">
                <StackPanel>
                    <RadioButton Content="Ham Sandwich"/>
                    <RadioButton Content="Soup"/>
                    <RadioButton Content="Wimpy Burger"/>
                </StackPanel>
            </TabItem>
        </TabControl>
        <TextBlock Grid.Row="1" Name="txtMessage" Margin="0,5,0,0"/>
    </Grid>

In our event handler, we simply change a text message, based on the tab that’s currently selected.

private void TabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    if ((sender as TabControl).SelectedIndex == 0)
        txtMessage.Text = "Start the day with a good breakfast";
    else
        txtMessage.Text = "Have something healthy for lunch";
}

905-001
905-002

#904 – Placing RadioButtons in a TabControl

If you like, you can place a group of RadioButton controls on each tab of a TabControl.  Because each tab of the TabControl can contain only a single element, you need to place the individual RadioButtons within a container (e.g. a StackPanel) which is then placed within the TabItem.

Because RadioButton selection is automatically managed, for all RadioButtons within the same container, this scheme ensures that only one RadioButton on each tab can be selected.

Below is an example.

    <TabControl Margin="10">
        <TabItem Header="Breakfast">
            <StackPanel>
                <RadioButton Content="Eggs"/>
                <RadioButton Content="Cereal"/>
                <RadioButton Content="Spam"/>
            </StackPanel>
        </TabItem>
        <TabItem Header="Lunch">
            <StackPanel>
                <RadioButton Content="Ham Sandwich"/>
                <RadioButton Content="Soup"/>
                <RadioButton Content="Wimpy Burger"/>
            </StackPanel>
        </TabItem>
        <TabItem Header="Dinner">
            <StackPanel>
                <RadioButton Content="Steak"/>
                <RadioButton Content="Fish"/>
                <RadioButton Content="Haggis"/>
            </StackPanel>
        </TabItem>
    </TabControl>

904-001

#903 – Placing Tabs on Different Sides of a TabControl

By default, the tabs on a TabControl will appear along the top edge of the control.

903-001

You can change which side of the TabControl that the tab strip appears on by using the TabStripPlacement property.  This property can have one of the following values: Top (default), Left, Bottom, or Right.

    <TabControl Margin="10" TabStripPlacement="Left">

903-002

    <TabControl Margin="10" TabStripPlacement="Bottom">

903-003

    <TabControl Margin="10" TabStripPlacement="Right">

903-004

#902 – The TabControl Automatically Creates Multiple Rows of Tabs

When you define a series of TabItems for a TabControlthe tabs will be displayed across the top of the control, next to each other.

902-001

 

If you have more tabs than will fit across the top of the TabControl, the tabs will automatically be wrapped to a second row.  The width of each tab will then be adjusted so that the total width of the tabs is spread across the control.

902-002

 

Tabs will also flow to multiple rows if you resize the TabControl so that the tabs no longer fit.  If we make the window shown above wider, the tabs will be moved back onto a single row.

902-003

 

Note that when you have more than one row, clicking on a tab makes that tab’s row the bottom row.

902-004

 

902-005