Search code examples
c#wpfxamlbrowser

TabControl with add button


So I'm building a Wpf Chromium Browser and right now I'm doing the Tabs. Everything works but the button to add a tab is handled as a own tab but it should only be a button. when i move it outside the tabcontrol, then the button is not positioned good and breaks everything.

<TabControl x:Name="TabControl" WindowChrome.IsHitTestVisibleInChrome="True" Background="Transparent" BorderThickness="0" Grid.Row="0" Grid.RowSpan="2">
    <TabItem HeaderTemplate="{DynamicResource TabHeaderTemplate}">
        <local:TabContent />
    </TabItem>
    <Button Content="+" Width="30" VerticalAlignment="Center" HorizontalAlignment="Left" Height="30" Click="AddNewTab_Click" />

</TabControl>

DataTemplate.xaml:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">


    <DataTemplate x:Key="TabHeaderTemplate">
        <Grid Height="32" Width="200">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="18"/>
                <ColumnDefinition/>
                <ColumnDefinition Width="18"/>
            </Grid.ColumnDefinitions>

            <Image Width="16" Height="16" HorizontalAlignment="Center" VerticalAlignment="Center"/>
            <TextBlock Text="New Document" VerticalAlignment="Center" HorizontalAlignment="Left" Grid.Column="1" FontSize="14" />
            <Button Content="X" Grid.Column="2" Padding="0" Width="16" Height="16" Background="Transparent" BorderBrush="Transparent"/>
        </Grid>
    </DataTemplate>

</ResourceDictionary>

enter image description here

enter image description here

As explained above I want that the tabs add button is a button and not a tab


Solution

  • Take a look at this example:

        public class ContentData
        {
            public string? Text { get; set; }
            public string? Header { get; set; }
        }
    
        public class DataViewModel : ViewModelBase
        {
            public ObservableCollection<ContentData> Content { get; } = new ObservableCollection<ContentData>();
    
    
            private static readonly string[] words = "As explained above I want that the tabs add button is a button and not a tab".Split();
    
            private RelayCommand? _addDataCommand;
            public RelayCommand AddDataCommand => _addDataCommand ??= new(() =>
            {
                ContentData data = new ContentData()
                {
                    Text = words[Content.Count],
                    Header = $"Tab #{Content.Count + 1}"
                };
                Content.Add(data);
                SelectedContent = data;
            });
    
            public ContentData SelectedContent { get => Get<ContentData>(); set => Set(value); }
        }
    
    <Window x:Class="Core2024.SO.ColinWalker.question79002772.AddTabWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:Core2024.SO.ColinWalker.question79002772"
            mc:Ignorable="d"
            Title="AddTabWindow" Height="450" Width="800"
            DataContext="{DynamicResource vm}">
        <Window.Resources>
            <local:DataViewModel x:Key="vm"/>
    
            <CompositeCollection x:Key="tabs.source">
                <CollectionContainer Collection="{Binding Content, Source={StaticResource vm}}"/>
                <TabItem>
                    <TabItem.Header>
                        <Button Content="+" Command="{Binding AddDataCommand, Source={StaticResource vm}}"/>
                    </TabItem.Header>
                </TabItem>
            </CompositeCollection>
    
            <DataTemplate x:Key="template.header"
                          DataType="{x:Type local:ContentData}">
                <TextBlock Text="{Binding Header}"/>
            </DataTemplate>
            <DataTemplate x:Key="template.content"
                          DataType="{x:Type local:ContentData}">
                <TextBlock Text="{Binding Text}"/>
            </DataTemplate>
        </Window.Resources>
    
        <Grid>
            <TabControl ItemsSource="{Binding Mode=OneWay, Source={StaticResource tabs.source}}"
                        SelectedItem="{Binding SelectedContent}"
                        ItemTemplate="{DynamicResource template.header}"
                        ContentTemplate="{DynamicResource template.content}"/>
        </Grid>
    </Window>