
Using a tabcontrol as a region for views in a CompositeWPF application is one thing, making them closeable can be a bit trickier. The sample in this article will show how you can modify a tabcontrol to allow closeable items.
Step 1: Make the custom header template and tabitem style
The first step is to modify the look of a tabitem header so it contains a close button while leaving room for the header content defined on the tab item. The XAML content required for this looks like the following:
<TabControl>
<TabControl.Resources>
<DataTemplate x:Key="CustomTabHeader">
<StackPanel Orientation="Horizontal">
<ContentPresenter>
<ContentPresenter.Content>
<Binding Path="Header">
<Binding.RelativeSource>
<RelativeSource Mode="FindAncestor"
AncestorType="{x:Type TabItem}"/>
</Binding.RelativeSource>
</Binding>
</ContentPresenter.Content>
</ContentPresenter>
<Button Margin="8,0,0,0" Command="local:Commands.CloseTabItem" CommandParameter="{Binding
RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type TabItem}}}"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center">
<Grid>
<Canvas Width="8" Height="8">
<Line X1="2" X2="6" Y1="2" Y2="6"
Stroke="Black" StrokeThickness="1"/>
<Line X1="6" X2="2" Y1="2" Y2="6"
Stroke="Black" StrokeThickness="1"/>
</Canvas>
</Grid>
</Button>
</StackPanel>
</DataTemplate>
<Style TargetType="TabItem">
<Style.Setters>
<Setter Property="HeaderTemplate"
Value="{StaticResource CustomTabHeader}"/>
</Style.Setters>
</Style>
</TabControl.Resources>
</TabControl>
Step 2: Closing tabitems
The second step is writing a little bit of code to close tabitems when the command is fired.
private void OnCloseTabItemExecute(object sender, ExecutedRoutedEventArgs e)
{
TabItem parent = e.Parameter as TabItem;
if (parent != null)
{
FrameworkElement view = (parent as TabItem).Content as FrameworkElement;
string regionName = RegionManager.GetRegionName(view);
_regionManager.Regions[regionName].Remove(view);
}
}
The first thing to do is find the tabitem that is quietly wrapped around the view that was added to the tabcontrol. This is done through a recursive search for parent framework elements until the tabitem is found. After that its a matter of retrieving the value of the RegionName attached property and removing the tabitem content from the region.
Conclusion
While a custom may look prettier over time it’s really not a requirement to make closable views in a compositeWPF application. Thanks to the powerful styling and templating features in WPF you can make the tabcontrol as fancy as you like without making it overly complex to work with.
— Update : The sample didn't work as expected. I have updated the sample code and made sure it works now. Please notify me if any more issues arise.
One comment
First of all, thank you for share your code, for my purposes is a valuable stuff. Another thing, could you be so kind and include the sample.
Gilberto Blanco.
Gilberto Blanco