TabControl- preventing user from changing the selected tab: MessageBox causing bug

admin

Administrator
Staff member
I've been pounding away at this issue for a little while, and have only found part of the solution.

I'm trying to set up a TabControl so that I can in some cases prevent the user from changing the currently selected tab. When the user is prevented from changing the currently selected tab, then they are shown a dialog box.

I have already read the following documents:

<ul>
<li><a href="https://stackoverflow.com/questions...tbox-scroll-position-when-itemssource-changes">WPF - reset ListBox scroll position when ItemsSource changes</a></li>
<li><a href="http://wizardsofsmart.net/uncategor...d-event-using-attached-dependency-properties/" rel="nofollow noreferrer">http://wizardsofsmart.net/uncategor...d-event-using-attached-dependency-properties/</a></li>
<li><a href="http://joshsmithonwpf.wordpress.com/2009/09/04/how-to-prevent-a-tabitem-from-being-selected/" rel="nofollow noreferrer">http://joshsmithonwpf.wordpress.com/2009/09/04/how-to-prevent-a-tabitem-from-being-selected/</a></li>
<li><a href="http://social.expression.microsoft.com/Forums/en-US/wpf/thread/f7b46018-1e97-4bbe-ada8-49b75dbc1da2/" rel="nofollow noreferrer">http://social.expression.microsoft.com/Forums/en-US/wpf/thread/f7b46018-1e97-4bbe-ada8-49b75dbc1da2/</a></li>
</ul>

I have implemented the solution indicated in the 3rd link (though all of the above create the same error seen below). And it works, <strong>but</strong>...

Things mess up thoroughly if the user does the following:

<ul>
<li>attempts to change the tab when such an action is disallowed. The MessageBox pops up with the error.</li>
<li>the user clicks "OK" and is returned to the original window.</li>
<li>the user tries again to change the tab. <strong>No MessageBox appears.</strong></li>
<li>if the user minimizes the window, and then maximizes it again, then the MessageBox that was supposed to appear earlier appears.</li>
<li>the user clicks "OK" and is returned to the original window... <strong>but the tab has been changed to the one they selected before, even though they should not be able to change tabs</strong>. </li>
</ul>

This is obviously <strong>not</strong> ideal behavior. <strong>Why isn't the MessageBox appearing the second time, and why is the tab changing when it should be disallowed from doing so?</strong>

If I remove the MessageBox part, it works fine.

Here is the code for the TabControl.SelectionChanged event handler:

Code:
bool _isChanging = false;

    private void tabControlForNavigation_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        if (!_isChanging &amp;&amp; canChangeTabs.IsChecked.HasValue)
        {
            _isChanging = true;


            bool canLeave = canChangeTabs.IsChecked.Value;  //normally this would be replaced by a check in the ViewModel

            if (!canLeave)
            {
                int prevIndex = tabControlForNavigation.Items.IndexOf(tabControlForNavigation.SelectedContent);
                tabControlForNavigation.SelectedIndex = prevIndex;
                MessageBox.Show("Can't change tabs!"); //if I comment out this line, everything works fine.
            }

            _isChanging = false;
        }
    }

I am using MVVM to implement this. The Window looks like this:

Code:
&lt;Window x:Class="TestTabControlSwitching.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow"
    Height="350"
    Width="525"&gt;
&lt;Grid&gt;
    &lt;Grid.RowDefinitions&gt;
        &lt;RowDefinition Height="Auto" /&gt;
        &lt;RowDefinition /&gt;
    &lt;/Grid.RowDefinitions&gt;
    &lt;CheckBox x:Name="canChangeTabs"
              Content="Can Change Tabs"
              IsChecked="True" /&gt;
    &lt;TabControl x:Name="tabControlForNavigation"
                Grid.Row="1"
                IsSynchronizedWithCurrentItem="True"
                ItemsSource="{Binding Collection}"
                SelectedItem="{Binding SelectedItem}"
                SelectionChanged="tabControlForNavigation_SelectionChanged"
                Margin="4"
                HorizontalAlignment="Stretch"&gt;
        &lt;TabControl.ItemTemplate&gt;
            &lt;DataTemplate&gt;
                &lt;ContentPresenter Content="{Binding Path=Name}" /&gt;
            &lt;/DataTemplate&gt;
        &lt;/TabControl.ItemTemplate&gt;

    &lt;/TabControl&gt;
&lt;/Grid&gt;



I'm omitting the rest of the code for sake of brevity- there is a pretty straight-forward ViewModel structure backing the window.