I write:

<DataTemplate x:Key="ClosableTabItemHeaderTemplate"> <DataTemplate.Resources> <BooleanToVisibilityConverter x:Key="B2V"/> </DataTemplate.Resources> <Grid Background="Transparent" HorizontalAlignment="Stretch" MinWidth="100" ToolTip="{Binding}"> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition/> </Grid.ColumnDefinitions> <ContentPresenter Content="{Binding}" Grid.Column="0" HorizontalAlignment="Center"/> <Button Name="CLOSE" Command="{Binding Path=CloseCommand}" Width="15" Height="15" Grid.Column="1" Template="{StaticResource CloseButtonTemplate}" Visibility="{Binding IsSelected, RelativeSource={RelativeSource FindAncestor, AncestorType=TabItem}, Converter={StaticResource B2V}}"/> </Grid> <DataTemplate.Triggers> <Trigger Property="IsMouseOver" Value="True"> <Setter TargetName="CLOSE" Property="Visibility" Value="Visible"/> </Trigger> </DataTemplate.Triggers> </DataTemplate> <TabControl ItemTemplate="{StaticResource ClosableTabItemHeaderTemplate}"> <TabControl.Items> <TabItem Header="This is test tab item with longer name." Width="100"/> <TabItem Header="Short name" Width="100"/> </TabControl.Items> </TabControl> 

But the pattern does not apply! What is the problem? :(

    1 answer 1

    When you specify Items or ItemsSource with elements of type TabItem , this will not work, because TabControl forms these TabItem'ы based on the specified ItemTemplate'а . Since your TabItem'ы has already been formed, TabControl will simply add it to the tab collection. If you want to change the template of the taba itself, then you need to slip it to some other class and form a template based on it. If you need to change the content of the taba itself ( what is inside ), use the TabControl.ContentTemplate .

    As an example, I rewrote your code a bit.

    XAML

     <Grid> <Grid.Resources> <DataTemplate x:Key="ClosableTabItemHeaderTemplate"> <DataTemplate.Resources> <BooleanToVisibilityConverter x:Key="B2V"/> </DataTemplate.Resources> <Grid Background="Transparent" HorizontalAlignment="Stretch" MinWidth="100" ToolTip="{Binding}"> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition/> </Grid.ColumnDefinitions> <TextBlock Text="{Binding Header}" Grid.Column="0" HorizontalAlignment="Center" Width="100"/> <Button Name="CLOSE" Command="{Binding CloseCommand}" CommandParameter="{Binding ID}" Width="15" Height="15" Grid.Column="1" Visibility="{Binding IsSelected, RelativeSource={RelativeSource FindAncestor, AncestorType=TabItem}, Converter={StaticResource B2V}}"/> </Grid> <DataTemplate.Triggers> <Trigger Property="IsMouseOver" Value="True"> <Setter TargetName="CLOSE" Property="Visibility" Value="Visible"/> </Trigger> </DataTemplate.Triggers> </DataTemplate> </Grid.Resources> <TabControl x:Name="TabControl" ItemsSource="{Binding Items}" ItemTemplate="{StaticResource ClosableTabItemHeaderTemplate}" > <TabControl.ContentTemplate> <DataTemplate> <StackPanel Orientation="Vertical"> <TextBlock Text="{Binding Header}" /> <TextBlock Text="Test" /> </StackPanel> </DataTemplate> </TabControl.ContentTemplate> </TabControl> </Grid> 

    Perhaps the implementation of ICommand would be superfluous, but still, I decided to insert it, for clarity.

    CODE

     public class Command : ICommand { public Command(Action<object> action) { this.action = action; } readonly Action<object> action; EventHandler canExecuteChanged; event EventHandler ICommand.CanExecuteChanged { add { canExecuteChanged += value; } remove { canExecuteChanged -= value; } } bool ICommand.CanExecute(object parameter) { return true; } void ICommand.Execute(object parameter) { action(parameter); } } public class ItemViewModel { public ItemViewModel(int id) { this.id = id; } readonly int id; public int ID { get { return id; } } public string Header { get; set; } public ICommand CloseCommand { get; set; } } public class Content { public Content(ICommand closeCommand) { items = new ObservableCollection<ItemViewModel>() { new ItemViewModel(0) { Header = "This is test tab item with longer name.", CloseCommand = closeCommand }, new ItemViewModel(1) { Header = "Short name", CloseCommand = closeCommand } }; } readonly IEnumerable<ItemViewModel> items; public IEnumerable<ItemViewModel> Items { get { return items; } } } public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); var closeCommand = new Command(CloseTab); DataContext = new Content(closeCommand); } void CloseTab(object tabID) { if(tabID == null) return; var id = (int)tabID; var items = (ObservableCollection<ItemViewModel>)TabControl.ItemsSource; items.Remove(items.First(x => x.ID == id)); } } 

    ObservableCollection used to send notifications about changes to this collection for the correct removal of TabItem'а .

    PS: It would be possible to implement INotifyPropertyChanged , but ObservableCollection enough in this situation

    • Exactly thanks, I set the tabs just for the test, I did not expect that the template would not spread to them. - PECHAIR