从子 UserControl 更改父 Window TabControl 的选项卡

Change tab of parent Window TabControl from child UserControl

我有一个父级 window,里面有一个 TabControl。每个选项卡都包含一个与之关联的 UserControl。在我的 UserControl 之一中,我有一个按钮。当我单击该按钮时,我想更改父项 window 中 TabControl 的选定选项卡。

我正在使用 MVVM 模式,所以如果可能的话,我想在 XAML 中使用按钮上的命令 属性 来完成。

例如:

<Button Content="Switch Tab" Command="{Binding SwitchTabCommand}" />

在此先感谢各位程序员!

父window视图模型:

public class CoolViewModel : BaseViewModel
{
    #region Properties

    public ObservableCollection<ITabViewModel> Tabs { get; set; }
    public ITabViewModel SelectedTab { get; set; }

    #endregion

    #region Constructor

    public CoolViewModel()
    {
        Tabs = new ObservableCollection<ITabViewModel>
        {
            new VeryNiceViewModel(),
            new VeryNiceViewModel()
        };
    }

    #endregion
}

下面是选项卡中 UserControl 的代码:

public class VeryCoolViewModel : BaseViewModel, ITabViewModel
{
    #region Properties

    public ObservableCollection<Test> Tests { get; set; }
    public Test currentSelection { get; set; }
    public string TabHeader { get; set; }

    #endregion

    #region Commands

    ICommand GoToOtherTab { get; set; }

    #endregion

    #region Constructor

    public GabaritSelecteurViewModel()
    {
        Tests = new ObservableCollection<Test>
        {
            new Test { Title = "Title #1" },
            new Test { Title = "Title #2" },
            new Test { Title = "Title #3" },
            new Test { Title = "Title #4" },
            new Test { Title = "Title #5" }
        };

        TabHeader = "Tests";

        GoToOtherTab = new RelayCommand(GoToTab, parameter => true);
    }

    #endregion

    #region Methods

    private void GoToTab(object parameter)
    {
        // I don't know how to tell to the
        // parent window to go to the other tab...
    }

    #endregion
}

这里是 UserControl(位于 TabControl 内)的 XAML:

<Button Content="Go to the other tab" Command="{Binding GoToOtherTab}" />

您可以尝试添加到 VeryCoolViewModel(您的 UserControl VM)事件中:

public class VeryCoolViewModel : BaseViewModel, ITabViewModel
{
    #region Properties

    public ObservableCollection<Test> Tests { get; set; }
    public Test currentSelection { get; set; }
    public string TabHeader { get; set; }

    public delegate void ChangeSelectedTab(string tabName)
    public event ChangeSelectedTab OnChangeSelectedTab
    #endregion

    #region Commands

    ICommand GoToOtherTab { get; set; }

    #endregion

    #region Constructor

    public GabaritSelecteurViewModel()
    {
        Tests = new ObservableCollection<Test>
        {
            new Test { Title = "Title #1" },
            new Test { Title = "Title #2" },
            new Test { Title = "Title #3" },
            new Test { Title = "Title #4" },
            new Test { Title = "Title #5" }
        };

        TabHeader = "Tests";

        GoToOtherTab = new RelayCommand(GoToTab, parameter => true);
    }

    private void GoToTab(object parameter)
    {
            OnChangeSelectedTab?.Invoke((string)parameter);
    }
}

并进入父 window 构造函数中的虚拟机:

public CoolViewModel()
{
    Tabs = new ObservableCollection<ITabViewModel>
    {
         new VeryNiceViewModel(),
         new VeryNiceViewModel()
    };
    Tabs.ForEach(x =>{
        x.OnChangeSelectedTab += x_OnChangeSelectedTab
    });

}

private void x_OnChangeSelectedTab(string tabName)
{
     // select from List of tabItems tabItem with name == tabName and then set propetry in this tabItem to true.
     SomePropertyInParentViewModel = true;
}

在视图中:

<TabItem x:Name="TabWhatYouNeed" IsSelected="{Binding SomePropertyInParentViewModel}">

您可以做一些 "hacky" 但非常简单的事情。如果您的每个 UserControl 都没有自己的 ViewModel(不太确定为什么需要这样做),那就不那么麻烦了。

无论如何,我们的目标是达到 CoolViewModel。我们怎么去那里? RelativeSource Binding。简而言之,它使您能够在不同的范围内进行绑定(除了您自己的 DataContext,在此示例中为 UserControl)。

因此,我们知道您有一个 TabControl,其中包含所有这些 UserControl,并且我们知道此 TabControl 的 DataContextCoolViewModel.

  1. 像这样把 Command 放在 CoolViewModel 中:

    public ICommand SwitchTabCommand {get;set;}

  2. 使用 UserControl 绑定到它:

    <Button Content="Go to the other tab" Command= "{Binding RelativeSource={RelativeSource AncestorType={x:Type TabControl}}, Path=DataContext.SwitchTabCommand}" />

所以基本上你正在寻找最近的祖先 TabControl,通过它 DataContext 寻找命令 SwitchTabCommand