locked
WPF TabControl's SelectionChanged event handler executing twice..! RRS feed

  • Question

  • Hi, I am having problems with an TabControl's event: SelectionChanged.

    the first problem I had was that my event was raised many times, so I Added this to my code:

    In my XAML:

    <TabControl Name="mainTabControl"  SelectionChanged="mainTabControl_SelectionChanged" >
    and in my code Behind:
    void mainTabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
            {
                if (e.Source is TabControl)
                {
                    // do some
                }
            }

    But, then I started having another problem which was because the event was trying to raise when the form wasnt loaded, so I added the following:

    void mainTabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
            {
                if (e.Source is TabControl)
                {
                    if (this.IsLoaded)
                    {
                        // do some  
                    }
                }
            }

    But my problem right now is that the FIRST time I try to change of tabItem the event raises TWICE and the selected tabItem remains the same, after doing that the event works as expected.

    How Can I solve the last problem? Am I doing something wrong?

    Tuesday, April 29, 2014 2:52 AM

Answers

  • Since the SelectionChanged is a routed event, it will bubble up from any other controls that also raise this same event. For example, if you have a ComboBox in a TabPage in your TabControl, the event handler will be called twice; once for the ComboBox and once for the TabControl. Please refer to the following link for more information: http://stackoverflow.com/questions/3659858/in-c-sharp-wpf-why-is-my-tabcontrols-selectionchanged-event-firing-too-often

    If you don't want the event to be raised when the window or whatever control that is hosting the TabControl loads, you should wait to hook up the event handler until it has been loaded, e.g.:

            public MainWindow()
            {
                InitializeComponent();
                this.Loaded += (s, e) => { mainTabControl.SelectionChanged += mainTabControl_SelectionChanged; };
     }
    
            void mainTabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
            {
                if (e.Source is TabControl)
                {
                    // do some
                }
            } 
    

    Don't hook up the event handler in XAML then:

            <TabControl Name="mainTabControl">
                <TabItem Header="1">
                    <ComboBox>
                        <ComboBoxItem>1</ComboBoxItem>
                        <ComboBoxItem>2</ComboBoxItem>
                        <ComboBoxItem>3</ComboBoxItem>
                    </ComboBox>
                </TabItem>
                <TabItem Header="2">
    
                </TabItem>
            </TabControl>
    


    Using the above sample code, the "//do some" code block is executed only when I actually switch tabs.

    Tuesday, April 29, 2014 9:01 AM

All replies

  • Hi, please try this:

    void mainTabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
            {
                if (e.OriginalSource != mainTabControl)
                {
                    return;
                }
    
                //do something
            }
    

    Tuesday, April 29, 2014 3:13 AM
  • I believe that you may have found a bug....I happened on it when attempting to recreate your problem.  If, in your event handler, you call anything that removes focus from the TabControl during the event handler, it seems to destabilize the TabControl.

    Here is my test stub:

    public partial class MainWindow : Window
     {
      private int m_EntranceCount;
    
      public MainWindow()
      {
       InitializeComponent();
       m_EntranceCount = 0;
      }
    
      private void OnTabSelectionChanged(object sender, SelectionChangedEventArgs e)
      {
       m_EntranceCount++;
       TabControl l_tabControl = sender as TabControl;
    
       if (IsLoaded && l_tabControl != null)
       {
        Trace.WriteLine(m_EntranceCount.ToString());
        //MessageBox.Show("Hello");
       }
      }
    
     }
    

    Running it like this, all goes well, but if you uncomment the MessageBox line, then everything goes wonky.  You can try and report it to Microsoft, but that is not going to solve your immediate problem.  If you are doing anything that removes focus from the TabControl during your event handler, try commenting out those parts and see if it solves your problem.


    It would be greatly appreciated if you would mark any helpful entries as helpful and if the entry answers your question, please mark it with the Answer link.

    Tuesday, April 29, 2014 4:03 AM
  • Since the SelectionChanged is a routed event, it will bubble up from any other controls that also raise this same event. For example, if you have a ComboBox in a TabPage in your TabControl, the event handler will be called twice; once for the ComboBox and once for the TabControl. Please refer to the following link for more information: http://stackoverflow.com/questions/3659858/in-c-sharp-wpf-why-is-my-tabcontrols-selectionchanged-event-firing-too-often

    If you don't want the event to be raised when the window or whatever control that is hosting the TabControl loads, you should wait to hook up the event handler until it has been loaded, e.g.:

            public MainWindow()
            {
                InitializeComponent();
                this.Loaded += (s, e) => { mainTabControl.SelectionChanged += mainTabControl_SelectionChanged; };
     }
    
            void mainTabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
            {
                if (e.Source is TabControl)
                {
                    // do some
                }
            } 
    

    Don't hook up the event handler in XAML then:

            <TabControl Name="mainTabControl">
                <TabItem Header="1">
                    <ComboBox>
                        <ComboBoxItem>1</ComboBoxItem>
                        <ComboBoxItem>2</ComboBoxItem>
                        <ComboBoxItem>3</ComboBoxItem>
                    </ComboBox>
                </TabItem>
                <TabItem Header="2">
    
                </TabItem>
            </TabControl>
    


    Using the above sample code, the "//do some" code block is executed only when I actually switch tabs.

    Tuesday, April 29, 2014 9:01 AM