以编程方式更改 TabControl 的选择适用于内容,但不适用于 tab/header

Changing selection of TabControl programatically works for content, but not for tab/header

我有一个 ListView 允许我 select 项目,然后将它们添加到 ObservableCollection。此 ObservableCollection 绑定到 TabControl,因此我在添加项目时获得新标签。我想要的是每个新标签都变成 selected 并自动显示其内容。

从内容的角度来看,这是可行的。我能够按预期看到 newly-added 项目的内容,但是从 TabControl 本身的外观来看,所有选项卡都已 "deselected," 或移至后台。

这是我正在做的事情:(请注意,我正在设置 SelectedItem。我在设置 SelectedIndex 或 SelectedValue 时遇到了类似的结果。不确定什么是最好的。)

void MyCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
    if (e.Action == NotifyCollectionChangedAction.Add)
    {
        List<MyClass> newStuff = e.NewItems.Cast<MyClass>().ToList<MyClass>();

        if (newStuff.Count == 1)
            myTabControl.SelectedItem = newStuff[0];
    }
}

使用 Console.WriteLine 和 TabControl 的 SelectionChanged 事件,我可以验证 TabControl.SelectedIndex 是否按预期更改。但是,对于每个新项目,所有选项卡似乎都移到了后台。

我总能看到新项目的内容,但我必须手动单击该选项卡才能使其在视觉上显示为前景选项卡。

每当我单击本应位于前台的后台选项卡时,我的控制台通常会显示多余的调试消息。

例如,如果我从 collection 中的零个项目开始,然后添加一个,我会得到一个背景选项卡、一条控制台消息,并且我会看到项目的内容。如果我单击选项卡,它会出现在前台并且 SelectionChanged 方法会触发(!!!),当我盯着相同的项目内容时重复相同的控制台消息:

myTabControl now has SelectedIndex of 0
myTabControl now has SelectedIndex of 0

如何以编程方式显示我的新选项卡的内容,并将该选项卡视为前景选项卡?

我可以通过编程将任何选项卡置于前台的唯一方法是设置 myTabControl.SelectedIndex = -1。显然这不是一个选项,而 ObservableCollection 包含项目,因此这会强制 TabControl 将第一个选项卡(内容、header 和所有)移动到前台。我在这里错过了什么?

更正: 使用此方法(设置 SelectedItem)我确实在前台获得了我的第一个选项卡,但是创建选项卡 #2 和所有后续选项卡 deselect所有选项卡,同时显示最近添加的内容。

这里出现了一些错误。

方法 MyCollection_CollectionChanged 在我的视图的代码隐藏(.xaml.cs 文件)中,而不是在 ViewModel 中。使用 Snoop 工具 (snoopwpf.codeplex.com),我能够确定索引以某种方式设置为超出范围。例如,如果我添加项目#4,该项目将被放置在索引 3 处,我将尝试更改为该索引。我的控制台日志消息会说所选索引已成功更改为 3,但是 Snoop 工具会说索引为 4(!),而所有四个选项卡似乎都在后台。真的很奇怪。其他集合对象可能会引发超出范围的异常,但此 TabControl 不会。

当我发现这个差一的错误时,我试图将索引设置为不是实际索引,而是索引减一。结果不是修复,而是预期的行为。如果我尝试将索引设置为应有的值,它会落在索引 + 1 上,但如果我尝试将其设置为索引 - 1,它实际上会将其更改为索引 - 1。这意味着我永远无法瞄准所需的目标选项卡,但始终向左移动一位,或向右移动一位(超出范围)。

我决定使用 ViewModel,而不是使用视图的代码隐藏从 NotifyCollectionChangedEventArgs 中挖掘出 MyClass 对象,以便它可以用于更改选项卡(这可能首先违反了 MVVM 模式)更改选项卡。这意味着将 TabControl 传递给 ViewModel,以便它可以添加到集合中,然后立即在下一行代码中更改选项卡,如下所示:

MyCollection.Add(newThing);
_tabControl.SelectedItem = newThing;

很有魅力!如果您看到未选择任何选项卡的 TabControl,请记住此修复。索引更改可能发生在错误的线程中,或者类似的事情。