title: TabControl SelectionChanged fires multiple times
body: <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>