简体   繁体   English

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

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

I have a ListView that allows me to select items, which are then added to an ObservableCollection . 我有一个ListView ,它允许我选择项目,然后将其添加到ObservableCollection This ObservableCollection is bound to a TabControl , so I get new tabs as I add items. ObservableCollection绑定到TabControl ,因此在添加项目时会得到新的选项卡。 What I would like is for each new tab to become selected and show its content automatically. 我希望每个新选项卡都被选中并自动显示其内容。

From a content perspective, this is working. 从内容的角度来看,这是可行的。 I am able to see the newly-added item's content as expected, however from the looks of the TabControl itself, all tabs have been "deselected," or moved to the background. 我能够按预期看到新添加项目的内容,但是从TabControl本身的外观来看,所有选项卡都已被“取消选择”或移到了后台。

Here's what I'm doing: (Note that I'm setting SelectedItem. I experience similar results when setting SelectedIndex or SelectedValue. Not sure what's best here.) 这是我正在做的事情:(请注意,我正在设置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];
    }
}

Using Console.WriteLine and the TabControl's SelectionChanged event, I can verify that the TabControl.SelectedIndex is changing as expected. 使用Console.WriteLine和TabControl的SelectionChanged事件,我可以验证TabControl.SelectedIndex是否按预期更改。 With each new item however, all tabs appear to move to the background. 但是,对于每个新项目,所有选项卡似乎都移到了背景。

I always see the content for the new item, but I must manually click the tab in order for it to visually appear as the foreground tab. 我总是看到新项目的内容,但是我必须手动单击该选项卡才能使其在外观上显示为前景选项卡。

Whenever I click the background tab that is supposed to already be in the foreground, my console often displays a redundant debug message. 每当我单击应该已经位于前台的“背景”选项卡时,控制台通常会显示一条冗余调试消息。

For example, if I start with zero items in the collection and then add one, I get one background tab, one console message, and I see the item's content. 例如,如果我从集合中的零个项目开始,然后添加一个,则得到一个背景标签,一条控制台消息,然后看到该项目的内容。 If I click on the tab, it comes to the foreground and the SelectionChanged method fires(!!!), repeating the same console message while I stare at the same item content: 如果我单击选项卡,它将出现在前台,并且SelectionChanged方法将触发(!!!),同时我凝视相同的项目内容时重复相同的控制台消息:

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

How can I both programmatically show the content of my new tab, and see that tab as the foreground tab? 如何既可以以编程方式显示新标签的内容,又可以将该标签视为前景标签?

The only way I can bring ANY tab to the foreground programmatically is by setting myTabControl.SelectedIndex = -1 . 我可以以编程方式将ANY选项卡置于前台的唯一方法是设置myTabControl.SelectedIndex = -1 Apparently this is not an option while the ObservableCollection contains items, so this forces the TabControl to move the first tab (content, header and all) to the foreground. 显然,当ObservableCollection包含项时,这不是一个选项,因此这迫使TabControl将第一个选项卡(内容,标题和全部)移动到前台。 What am I missing here? 我在这里想念什么?

Correction: With this method (setting SelectedItem ) I do get my very first tab in the foreground, however creating tab #2 and all subsequent tabs deselects all tabs, while showing the content from the most recent addition. 更正:使用此方法(设置SelectedItem ),我确实将我的第一个标签放在前台,但是创建标签#2和所有随后的标签会取消选择所有标签,同时显示最新添加的内容。

Some off-by-one bug was occurring here. 这里发生了一些错误的错误。

The method MyCollection_CollectionChanged was in my View's code-behind (the .xaml.cs file) rather than in the ViewModel. 方法MyCollection_CollectionChanged在我的View的代码隐藏(.xaml.cs文件)中,而不是在ViewModel中。 Using the Snoop tool (snoopwpf.codeplex.com) I was able to determine that the index was being set out-of-range somehow. 使用探听工具(snoopwpf.codeplex.com),我能够确定索引设置是否超出范围。 For example, if I added item #4, the item would be placed at index 3, and I would attempt to change to this index. 例如,如果我添加了项目#4,则该项目将放置在索引3处,而我将尝试更改为该索引。 My console log messages would say that the selected index was successfully changed to 3, however the Snoop tool would say the index is 4(!) while all four tabs appeared to be in the background. 我的控制台日志消息会说所选索引已成功更改为3,但是Snoop工具会说索引为4(!),而所有四个选项卡似乎都在后台。 Truly bizarre. 真的很奇怪。 Other collection objects might throw an out-of-range exception, but not this TabControl. 其他集合对象可能会引发超出范围的异常,但不会引发此TabControl。

When I discovered this off-by-one bug, I attempted to set the index not to the actual index, but to the index minus one. 当我发现此异常问题时,我尝试将索引设置为不是实际索引,而是设置为负索引。 The result was not a fix, but expected behavior instead. 结果不是修复,而是预期的行为。 If I tried to set the index to what it should be, it would land on index + 1, but if I tried setting it to index - 1, it would actually change it to index - 1. This meant I could never target the desired tab, but always go one to the left, or one to the right (out-of-range). 如果我尝试将索引设置为应有的值,它将落在索引+ 1上,但是如果我尝试将其设置为索引-1,则实际上会将其更改为索引-1。这意味着我永远无法定位期望的目标标签,但始终向左或向右走一圈(超出范围)。

Rather than use the View's code-behind to dig the MyClass object out of the NotifyCollectionChangedEventArgs so that it could be used to change tabs (which probably violates the MVVM pattern in the first place), I decided to use the ViewModel to change tabs. 我决定使用ViewModel来更改选项卡,而不是使用View的背后代码从NotifyCollectionChangedEventArgs中挖掘MyClass对象,以便可以用来更改选项卡(首先可能违反了MVVM模式)。 This meant passing the TabControl to the ViewModel, so that it could to add to the collection and then immediately change tabs on the next line of code, like so: 这意味着将TabControl传递给ViewModel,以便可以将其添加到集合中,然后立即在下一行代码中更改选项卡,如下所示:

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

Works like a charm! 奇迹般有效! Keep this fix in mind if you ever see a TabControl with no tabs selected. 如果您看到没有选择选项卡的TabControl,请记住此修复程序。 The index change may be taking place in the wrong thread, or some such thing. 索引更改可能发生在错误的线程中,或发生了某些此类事情。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM