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?

Était-ce utile?

La 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);
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top