Reputation: 2937
I have a Tabcontrol on my MainWindow to display child views. On the ItemTemplate I Add a button to close every tab and SelectedItem and ItemSource are Binded to propertys of my viewModel (SelectedTab and Tabs). When the close button is executed I call an ICommand from VM to close the tab.
This is an extract of MainWindow.XAML
<TabControl Grid.Row="1" Grid.Column="1" BorderThickness="0" Name="TabViews" Background="Transparent" ItemsSource="{Binding Tabs}" SelectedItem="{Binding SelectedTab}">
<TabControl.ItemTemplate>
<DataTemplate>
<StackPanel Margin="2" Orientation="Horizontal" Background="Transparent">
<TextBlock FontSize="18" Text="{Binding Header}" Margin="0 0 10 0"/>
<Button Content="X"
Command="{Binding RelativeSource=
{RelativeSource FindAncestor,
AncestorType={x:Type TabControl}},
Path= DataContext.CloseTabCommand}"
Width="25" Height="25" FontFamily="Verdana" FontWeight="UltraBold" Background="Transparent" FontSize="10"/>
</StackPanel>
</DataTemplate>
</TabControl.ItemTemplate>
</TabControl>
This is an extract of my viewModel:
public ICommand CloseTabCommand
{
get
{
if (_closeTabCommand == null)
_closeTabCommand = new RelayCommand(param => this.CloseTab(), null);
return _closeTabCommand;
}
}
private void CloseTab()
{
this.Tabs.Remove(this.SelectedTab);
}
public MyTabItem SelectedTab
{
get
{
return _selectedTab;
}
set
{
_selectedTab = value;
OnPropertyChanged("SelectedTab");
}
}
As you can see i'm ussing (I know this is wrong):
this.Tabs.Remove(this.SelectedTab);
That refears to the current selected tab. But if i click the button from a tab different than the selected the command is executed anyway and remove the selected tab instead of the clicked one. So my question is how can i get a reference for the clicked tab button instead of the selected one so I can removeit from my collection? Maybe a command parameter form XAML with a reference to clicked tab? Thanks!
UPDATE
I got it working thanks to @Rohit Vats help. Now i'm tryn to call the same command but from a different XAML usercontrol, loaded inside a conterpresenter on the TabControl:
<TabControl Grid.Row="1" Grid.Column="1" BorderThickness="0" Name="TabViews" Background="Transparent" ItemsSource="{Binding Tabs}" SelectedItem="{Binding SelectedTab}">
<TabControl.ItemTemplate>
<DataTemplate>
<StackPanel Margin="2" Orientation="Horizontal" Background="Transparent">
<TextBlock FontSize="18" Text="{Binding Header}" Margin="0 0 10 0"/>
<Button Style="{DynamicResource MetroCircleButtonStyle}" Content="X"
Command="{Binding RelativeSource=
{RelativeSource FindAncestor,
AncestorType={x:Type TabControl}},
Path= DataContext.CloseTabCommand}"
CommandParameter="{Binding}"
Width="25" Height="25" FontFamily="Verdana" FontWeight="UltraBold" Background="Transparent" FontSize="10"/>
</StackPanel>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<ContentPresenter Grid.Row="1" Grid.Column="1" x:Name="ContentArea" Content="{Binding Content}"/>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
This is the code for the button on Client view:
<Button Name="cmdCerrar" Grid.Row="0" Grid.Column="5" Margin="5"
Command="{Binding RelativeSource=
{RelativeSource FindAncestor,
AncestorType={x:Type TabControl}},
Path= DataContext.CloseTabCommand}"
CommandParameter="{Binding DataContext, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=TabItem}}"
>Cerrar</Button>
And this is the code i use on MainWIndow ViewModel to créate the child view:
public ICommand CreateViewsCommand
{
get
{
if(_createViewsCommand==null)
_createViewsCommand = new RelayCommand(
(classtype) =>
{
if (classtype != null)
{
bool bFound=false;
foreach (MyTabItem myTab in _tabs)
{
if (myTab.Content.GetType().ToString() == classtype.ToString())
{
bFound = true;
SelectedTab = myTab;
}
}
if (!bFound) CreateView = (UserControl)Activator.CreateInstance(classtype as Type);
}
});
return _createViewsCommand;
}
}
public UserControl CreateView
{
get
{
return _createView;
}
set
{
if (value != _createView)
{
_createView = value;
var myTab = new MyTabItem { Header = value.GetType().Name, Content = value };
Tabs.Add(myTab);
this.SelectedTab = myTab;
OnPropertyChanged("CreateView");
}
}
}
And by last this is the command i want to call:
private void CloseTab(object param)
{
MyTabItem tabItem = (MyTabItem)param;
this.Tabs.Remove(tabItem);
}
When i call it from a button on MainWindow it Works. But from child window, param get null. Any ideas?
Upvotes: 0
Views: 1915
Reputation: 81243
Pass DataContext
as CommandParameter
which will point to the object instance of TabItem on which button is clicked.
<Button Content="X"
Command="{Binding RelativeSource= {RelativeSource FindAncestor,
AncestorType={x:Type TabControl}},
Path= DataContext.CloseTabCommand}"
CommandParameter="{Binding}"
Width="25" Height="25" FontFamily="Verdana" FontWeight="UltraBold"
Background="Transparent" FontSize="10"/>
and pass parameter to command method and remove the passed value from the source collection instead of selected tab:
public ICommand CloseTabCommand
{
get
{
if (_closeTabCommand == null)
_closeTabCommand = new RelayCommand(param => this.CloseTab(param),
null);
return _closeTabCommand;
}
}
private void CloseTab(object param)
{
TabItem tabItem = (TabItem)param;
this.Tabs.Remove(tabItem);
}
Upvotes: 3