TabControl SelectionChanged fires multiple times
<p>We have our own <code>TabControl</code> class which does an override on <code>OnSelectionChanged</code>.</p>

<p>The relevant code is:</p>

<pre><code>protected override void OnSelectionChanged(SelectionChangedEventArgs e)
    {
        base.OnSelectionChanged(e);
        UpdateSelectedItem();
    }


    internal Grid ItemsHolder { get; set; }

    public TabControl()
        : base()
    {
        ItemsHolder = new Grid();
        // this is necessary so that we get the initial databound selected item
        this.ItemContainerGenerator.StatusChanged += ItemContainerGenerator_StatusChanged;
    }


    /// &lt;summary&gt;
    /// if containers are done, generate the selected item
    /// &lt;/summary&gt;
    /// &lt;param name="sender"&gt;&lt;/param&gt;
    /// &lt;param name="e"&gt;&lt;/param&gt;
    void ItemContainerGenerator_StatusChanged(object sender, EventArgs e)
    {
        if (this.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
        {
            this.ItemContainerGenerator.StatusChanged -= ItemContainerGenerator_StatusChanged;
            UpdateSelectedItem();
        }
    }

    private bool _isTemplateApplied = false;
    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();
        var itemsHolderParent = GetTemplateChild("PART_ItemsHolderParent") as Panel;
        if (itemsHolderParent != null)
        {
            var parent = ItemsHolder.Parent as Panel;
            if (parent != null)
                parent.Children.Remove(ItemsHolder);
            itemsHolderParent.Children.Add(ItemsHolder);
            if (parent != null)
                ItemContainerGenerator.StatusChanged += ItemContainerGenerator_StatusChanged;
            UpdateSelectedItem();
        }
        _isTemplateApplied = true;
    }


    internal void ClearChildren()
    {
        foreach (var cp in ItemsHolder.Children.OfType&lt;ContentPresenter&gt;())
            cp.Content = null;
        ItemsHolder.Children.Clear();
    }

    /// &lt;summary&gt;
    /// when the items change we remove any generated panel children and add any new ones as necessary
    /// &lt;/summary&gt;
    /// &lt;param name="e"&gt;&lt;/param&gt;
    protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e)
    {
        base.OnItemsChanged(e);

        switch (e.Action)
        {
            case NotifyCollectionChangedAction.Reset:
                var removeList = new List&lt;ContentPresenter&gt;();
                foreach (var presenter in ItemsHolder.Children.OfType&lt;ContentPresenter&gt;())
                    removeList.Add(presenter);
                var oldItemsCount = removeList.Count;

                foreach (var item in Items)
                {
                    var itemPresenter = FindChildContentPresenter(item);
                    if (removeList.Contains(itemPresenter))
                        removeList.Remove(itemPresenter);
                }

                foreach (var removePresenter in removeList)
                    ItemsHolder.Children.Remove(removePresenter);

                //If there were old items, the SelectionChanged in the Selector will force a new selected item
                //If there are no items we can't update the selected item (there is nothing to select)
                //If the tempalte is not yet applied, applying the template will select the tabitem
                if (oldItemsCount == 0 &amp;&amp; Items != null &amp;&amp; Items.Count &gt; 0 &amp;&amp; _isTemplateApplied)
                    UpdateSelectedItem();
                break;

            case NotifyCollectionChangedAction.Add:
            case NotifyCollectionChangedAction.Remove:
                if (e.OldItems != null)
                {
                    foreach (var item in e.OldItems)
                    {
                        ContentPresenter cp = FindChildContentPresenter(item);
                        if (cp != null)
                        {
                            ItemsHolder.Children.Remove(cp);
                        }
                    }
                }

                // don't do anything with new items because we don't want to
                // create visuals that aren't being shown

                UpdateSelectedItem();
                break;

            case NotifyCollectionChangedAction.Replace:
                throw new NotImplementedException("Replace not implemented yet");
        }
    }

    /// &lt;summary&gt;
    /// generate a ContentPresenter for the selected item
    /// &lt;/summary&gt;
    internal void UpdateSelectedItem()
    {
        if (SelectedIndex == -1 &amp;&amp; Items != null &amp;&amp; Items.Count &gt; 0)
            SelectedIndex = 0;
        if (SelectedIndex == -1)
            return;

        // generate a ContentPresenter if necessary
        TabItem item = GetSelectedTabItem();
        if (item != null)
        {
            FindOrElseCreateChildContentPresenter(item);
        }

        // show the right child
        foreach (ContentPresenter child in ItemsHolder.Children.OfType&lt;ContentPresenter&gt;())
        {
            if ((child.Tag as TabItem).IsSelected)
                SelectedTabItem = child.Tag as TabItem;
            child.Visibility = ((child.Tag as TabItem).IsSelected) ? Visibility.Visible : Visibility.Collapsed;
        }
    }


    /// &lt;summary&gt;
    /// create the child ContentPresenter for the given item (could be data or a TabItem)
    /// &lt;/summary&gt;
    /// &lt;param name="item"&gt;&lt;/param&gt;
    /// &lt;returns&gt;&lt;/returns&gt;
    internal ContentPresenter FindOrElseCreateChildContentPresenter(object item)
    {
        if (item == null)
        {
            return null;
        }

        ContentPresenter cp = FindChildContentPresenter(item);

        if (cp != null)
        {
            cp.Tag = (item is TabItem) ? item : (this.ItemContainerGenerator.ContainerFromItem(item));
            return cp;
        }

        // the actual child to be added.  cp.Tag is a reference to the TabItem
        cp = new ContentPresenter();
        cp.Content = (item is TabItem) ? (item as TabItem).Content : item;

        Dispatcher.BeginInvoke(new Action(() =&gt;
        {
            cp.ContentTemplate = this.SelectedContentTemplate;
            cp.ContentTemplateSelector = this.SelectedContentTemplateSelector;
            cp.ContentStringFormat = this.SelectedContentStringFormat;
        }), System.Windows.Threading.DispatcherPriority.Send);


        cp.Visibility = Visibility.Collapsed;
        cp.Tag = (item is TabItem) ? item : (this.ItemContainerGenerator.ContainerFromItem(item));
        ItemsHolder.Children.Add(cp);
        return cp;
    }

    /// &lt;summary&gt;
    /// Find the CP for the given object.  data could be a TabItem or a piece of data
    /// &lt;/summary&gt;
    /// &lt;param name="data"&gt;&lt;/param&gt;
    /// &lt;returns&gt;&lt;/returns&gt;
    public ContentPresenter FindChildContentPresenter(object data)
    {
        if (data is TabItem)
        {
            data = (data as TabItem).Content;
        }

        if (data == null)
        {
            return null;
        }

        foreach (ContentPresenter cp in ItemsHolder.Children.OfType&lt;ContentPresenter&gt;())
        {
            if (cp.Content == data)
            {
                return cp;
            }
        }

        return null;
    }

    /// &lt;summary&gt;
    /// copied from TabControl; wish it were protected in that class instead of private
    /// &lt;/summary&gt;
    /// &lt;returns&gt;&lt;/returns&gt;
    protected TabItem GetSelectedTabItem()
    {
        object selectedItem = base.SelectedItem;
        if (selectedItem == null)
        {
            return null;
        }
        TabItem item = selectedItem as TabItem;
        if (item == null)
        {
            item = base.ItemContainerGenerator.ContainerFromIndex(base.SelectedIndex) as TabItem;
        }
        return item;


    }



    internal TabItem SelectedTabItem
    {
        get { return (TabItem)GetValue(SelectedTabItemProperty); }
        set { SetValue(SelectedTabItemProperty, value); }
    }

    // Using a DependencyProperty as the backing store for SelectedTabItem.  This enables animation, styling, binding, etc...
    internal static readonly DependencyProperty SelectedTabItemProperty =
        DependencyProperty.Register("SelectedTabItem", typeof(TabItem), typeof(TabControl), new UIPropertyMetadata(null));
</code></pre>

<p>When I use the debugger I see that sometimes the <code>OnSelectionChanged</code> is fired multiple times for one tab switch. Is this a bug? How can I fix this? Or is it intended behaviour and can I use another event to detect tab switches?</p>