+1  A: 

It sounds like you just need to run your algorithm again when the collection changes. Since you are testing the ItemContainerGenerator.Status property, the algorithm may not run. You may want to consider listening to the StatusChanged event, and when it changes to ContainersGenerated run the algorithm again.

Abe Heidebrecht
I have tried this and it still does not show up correctly. Also, the ItemContainerGenerator.StatusChanged event runs before the SelectedItem is updated so setting it always sets the selected tab to the last-selected tab. By using breakpoints I can see that the Panel.ZIndex is definitely getting set correctly when adding/removing tabs using the TabControl_SelectionChanged event, however it does not draw them the way it should. To me this doesn't make sense since Drag/Dropping tabs (which also removes and re-adds the tabItem) draws the tab order correctly.
Rachel
Abe Heidebrecht
+1  A: 

Thank you Abe, your second comment lead me to my solution!

I added tabItem.Dispatcher.Invoke(DispatcherPriority.Render, EmptyDelegate); to each iteration of the loop.

I would still be interested in learning if anyone else finds a way around this without refreshing each tabItem on every change. I tried refreshing the entire tab control at the end of the loop but that only worked for closing tabs, not adding them. I know that Panel.ZIndex is getting set correctly, it's just not honoring that property when rendering.

EDIT: The above line of code was causing an unusual flicker when Dragging/Dropping the tabs that would briefly show the tab behind the one being dragged. I moved the code to a separate function and called it at a lower dispatcher priority and this fixed the problem. Final code is below:

private void PrimaryTabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        if (e.Source is TabControl)
        {
            TabControl tabControl = sender as TabControl;

            tabControl.Dispatcher.BeginInvoke(
                new Action(() => UpdateZIndex(sender as TabControl)),
                DispatcherPriority.Background);
        }
    }

    private void UpdateZIndex(TabControl tabControl)
    {
        ItemContainerGenerator icg = tabControl.ItemContainerGenerator;

        if (icg.Status == System.Windows.Controls.Primitives.GeneratorStatus.ContainersGenerated)
        {
            foreach (object o in tabControl.Items)
            {
                UIElement tabItem = icg.ContainerFromItem(o) as UIElement;
                if (tabItem != null)
                {
                    // Set ZIndex
                    Panel.SetZIndex(tabItem, (o == tabControl.SelectedItem ? 100 :
                        90 - tabControl.Items.IndexOf(o)));
                }
            }
        }
    }
Rachel
Upgrading to .Net 4.0 also fixed the problem
Rachel