skybluecodeflier
skybluecodeflier

Reputation: 1349

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

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:

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

Things mess up thoroughly if the user does the following:

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

If I remove the MessageBox part, it works fine.

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

bool _isChanging = false;

    private void tabControlForNavigation_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        if (!_isChanging && 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:

<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">
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition />
    </Grid.RowDefinitions>
    <CheckBox x:Name="canChangeTabs"
              Content="Can Change Tabs"
              IsChecked="True" />
    <TabControl x:Name="tabControlForNavigation"
                Grid.Row="1"
                IsSynchronizedWithCurrentItem="True"
                ItemsSource="{Binding Collection}"
                SelectedItem="{Binding SelectedItem}"
                SelectionChanged="tabControlForNavigation_SelectionChanged"
                Margin="4"
                HorizontalAlignment="Stretch">
        <TabControl.ItemTemplate>
            <DataTemplate>
                <ContentPresenter Content="{Binding Path=Name}" />
            </DataTemplate>
        </TabControl.ItemTemplate>

    </TabControl>
</Grid>

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

Upvotes: 5

Views: 5592

Answers (4)

Gareth White
Gareth White

Reputation: 31

You are missing an easy trick. Just make focusable=False for the Tab header.

<TabItem Header="MY TAB" Focusable="False">

You could bind this property to your view model.

<TabItem Header="MY TAB" Focusable="{Binding Bool_CanHasCheeseBurger}">

Upvotes: 0

lakshminb7
lakshminb7

Reputation: 1602

This was a very detailed question. I had the same problem you had (i.e. the message box doesn't display on 2nd or 3rd selection changed until you minimize and maximize the window) and after much debugging and multiple google searches, stumbled on the below linked MSDN forum post.

[TabControl SelectionChanged Strange Behaviour?]

Please ignore the poorly formatted question and answer. But as mentioned in the answer, putting it inside a dispatcher and focussing the selected tab after setting the index resolved the issue for me.

Upvotes: 0

Brandon Bearden
Brandon Bearden

Reputation: 850

I know this post is a bit old, but I have a very easy way to accomplish this:

Use the tab_Enter event and create a method that performs your check and displays a MessageBox to the user and then set myTabs.SelectedIndex to the prior index. A simple example:

    private void someTab_Enter(object sender, EventArgs e)
    {
        if (myCondition)
        {
            MessageBox.Show("Sorry, myCondition will not let you move to this tab.");
            myTabs.SelectedIndex = someOtherTabIndex;
        }
    }

Upvotes: 0

Fredrik Hedblad
Fredrik Hedblad

Reputation: 84657

As you noticed, the problem is the MessageBox inside the event handler. The focus will change to the MessageBox and you can get all kind of undesired effects. I've had my own problems with this.

Here is a couple of SO question on the same subject
WPF: Does MessageBox Break PreviewMouseDown?
Wpf stop routing event when MessageBox appear?

If you must display a message to the user then an alternate approach might be to create a new Window which you style like a MessageBox and then call Show (not ShowDialog) on it inside the event handler.

Upvotes: 6

Related Questions