I have a TabControl with a special "+ tab" that is defined as such:
<TabControl x:Name="ProjectsTabControl">
<local:ProjectTabItem x:Name="AddProjectTabTabItem" Header="+" MouseUp="AddProjectButton_Click" PreviewMouseDown="AddProjectTabTabItem_PreviewMouseDown"/>
</TabControl>
"MouseDown" simply marks the mouse event args as handled (in order to prevent +the tab from being selected). "Button_Click" adds a new tab with the following style:
<Window.Resources>
<Style x:Key="CloseableTabItemStyle" TargetType="local:ProjectTabItem">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<DockPanel>
<TextBlock Text="{Binding}" Margin="0,0,5,0"/>
<Button Content="X" Click="CloseButton_Click" Tag="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:ProjectTabItem}}}"/>
</DockPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
These are my "actual" tabs that I use. Each such tab has a "close button" in its header. As you can see, the close button's tag is set to a ProjectTabItem ancestor.
My CloseButton logic is as follows:
private async void CloseButton_Click(object sender, RoutedEventArgs e)
{
if (sender is Button closeButton && closeButton.Tag is ProjectTabItem tabItem)
{
ProjectsTabControl.Items.Remove(tabItem);
if (ProjectsTabControl.SelectedIndex == ProjectsTabControl.Items.Count - 1)
{
ProjectsTabControl.SelectedIndex--;
}
}
}
The idea here is to prevent the +tab from being selected (however, the issue that I will soon describe happens even if I let the +tab be selected).
When I close the last tab (i.e., the last tab before the +tab), I see the following error
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.TabControl', AncestorLevel='1''. BindingExpression:Path=TabStripPlacement; DataItem=null; target element is 'ProjectTabItem' (Name=''); target property is 'NoTarget' (type 'Object')
This only happens when the tab is selected when closing it.
It seems like if I preemptively open a new tab before closing the "last" one, the issue does not happen. (However, this does not help me as I would like to allow having no tabs at all, except the +tab.)
What is causing this? How do I fix it?
Edit: I've found a, I guess, workaround here. Setting tabItem.Template = null; before removing the tab actually fixes the issue. So let me change my question to: why does this happen? and is this "solution" actually a solution or does it simply supresses some underlying important issue in my code?
You will never have fun with WPF as long as you use code-behind. You will always step in the 'workaround - trap'. If you follow the MVVM-Pattern, things will get much easier.
I just created in my app a TabControl wich is bound to an Observable Collection
In this Observable Collection are TabItemModels:
Here the XAML - Part of this TabControl:
Declarations in MainViewModel:
The button in XAML triggers the Relay-Command in the TabItemModel wich sends a message to the View-Model to close the tab. I just remove this particular Model from the Collection:
Works fine for me.