Question

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?

Was it helpful?

Solution

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);
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top