【问题标题】:Remove TabControl Tab different than the selected one with MVVM使用 MVVM 删除与所选选项不同的 TabControl 选项卡
【发布时间】:2014-05-24 07:49:49
【问题描述】:

我的 MainWindow 上有一个 Tabcontrol 来显示子视图。在 ItemTemplate 上,我添加了一个按钮来关闭每个选项卡,并且 SelectedItem 和 ItemSource 绑定到我的视图模型(SelectedTab 和选项卡)的属性。执行关闭按钮时,我从 VM 调用 ICommand 以关闭选项卡。

这是 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>

这是我的 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");
        }
    }

如你所见,我正在使用(我知道这是错误的):

this.Tabs.Remove(this.SelectedTab);

指的是当前选定的标签。但是,如果我从与所选选项卡不同的选项卡单击按钮,则无论如何都会执行命令并删除所选选项卡而不是单击的选项卡。所以我的问题是如何获得单击的选项卡按钮而不是选定的按钮的参考,以便我可以从我的收藏中删除它?也许是 XAML 格式的命令参数,并引用了单击的选项卡? 谢谢!

更新

感谢@Rohit Vats 的帮助,我得到了它的帮助。现在我尝试调用相同的命令,但来自不同的 XAML 用户控件,加载在 TabControl 上的 conterpresenter 中:

<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>

这是客户端视图按钮的代码:

<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>

这是我在 MainWINdow ViewModel 上用来创建子视图的代码:

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");
            }
        }
    }

最后这是我要调用的命令:

 private void CloseTab(object param)
    {
        MyTabItem tabItem = (MyTabItem)param;
        this.Tabs.Remove(tabItem);            
    }

当我从 MainWindow 上的按钮调用它时,它可以工作。但是从子窗口中,参数为空。有什么想法吗?

【问题讨论】:

    标签: c# wpf mvvm tabcontrol


    【解决方案1】:

    将 DataContext 传递为 CommandParameter,这将指向单击按钮的 TabItem 的对象实例。

    <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"/>
    

    并将参数传递给命令方法并从源集合而不是选定的选项卡中删除传递的值:

    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);
    }
    

    【讨论】:

    • 优秀的答案!!!谢谢你像魅力一样工作!问题:这是什么意思“CommandParameter="{Binding}"”。看起来好像没有绑定。
    • CommandParameter="{Binding}" - 如果您不提供任何路径,则绑定引擎将通过 DataContext 控制权,在您的情况下为 TabItem。
    • 太棒了!非常感谢我的朋友!
    • 抱歉,我可以再问一件事吗?我正在尝试从 ContentPresenter 上的选项卡内加载不同 xaml (userControl) 的按钮使用相同的命令。该命令被调用,但参数是对该用户控制 VM 的引用。在这种情况下,如何修改 CommandParameter 以访问 Tab DataContext?谢谢!
    • 试试这个 - "{Binding DataContext, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=TabItem}"。如果 Button 是 TabItem 的可视子级,这将起作用。
    猜你喜欢
    • 1970-01-01
    • 2017-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-26
    • 2013-07-08
    • 1970-01-01
    相关资源
    最近更新 更多