TabControl-阻止用户更改选定的选项卡:MessageBox导致错误

时间:2011-09-06 22:46:38

标签: c# wpf xaml mvvm tabcontrol

我一直在讨论这个问题,并且只找到了部分解决方案。

我正在尝试设置TabControl,以便在某些情况下可以阻止用户更改当前选定的标签。当阻止用户更改当前选定的选项卡时,将显示一个对话框。

我已阅读以下文件:

我已经实现了第3个链接中指示的解决方案(尽管以上所有内容都会产生相同的错误)。它有效, ......

如果用户执行以下操作,事情会彻底搞乱:

  • 尝试在不允许此类操作时更改标签。消息框弹出错误。
  • 用户点击“确定”并返回原始窗口。
  • 用户再次尝试更改标签。 不显示MessageBox。
  • 如果用户最小化窗口,然后再次将其最大化,则会出现之前应该出现的MessageBox。
  • 用户点击“确定”并返回原始窗口... 但该标签已更改为之前选择的标签,即使它们无法更改标签

这显然是理想行为。 为什么MessageBox不会第二次出现,为什么不应该禁用此选项卡?

如果删除MessageBox部分,它可以正常工作。

以下是TabControl.SelectionChanged事件处理程序的代码:

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;
        }
    }

我正在使用MVVM来实现这一点。窗口看起来像这样:

<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>

为了简洁起见,我省略了其余的代码 - 支持窗口的是一个非常简单的ViewModel结构。

4 个答案:

答案 0 :(得分:5)

正如您所注意到的,问题是事件处理程序中的MessageBox。焦点将变为MessageBox,您可以获得各种不受欢迎的效果。我对此有自己的问题。

以下是关于同一主题的几个问题 WPF: Does MessageBox Break PreviewMouseDown?
Wpf stop routing event when MessageBox appear?

如果您必须向用户显示消息,则替代方法可能是创建一个新的Window,其样式为MessageBox,然后调用Show ShowDialog)在事件处理程序内部。

答案 1 :(得分:0)

我知道这篇文章有点陈旧,但我有一个非常简单的方法来实现这个目标:

使用tab_Enter事件并创建一个执行检查的方法,并向用户显示MessageBox,然后将myTabs.SelectedIndex设置为先前的索引。一个简单的例子:

    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;
        }
    }

答案 2 :(得分:0)

这是一个非常详细的问题。我遇到了同样的问题(即消息框没有显示在第二或第三选择上,直到你最小化并最大化窗口)并经过大量调试和多次谷歌搜索后,偶然发现了以下链接的MSDN论坛帖子。

[TabControl SelectionChanged Strange Behaviour?]

请忽略格式错误的问题和答案。但正如答案中所提到的,将其放入调度员并在设置索引后将选定的选项卡集中在一起解决了我的问题。

答案 3 :(得分:0)

你错过了一个简单的伎俩。只需为Tab标题设置focusable = False即可。

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

您可以将此属性绑定到视图模型。

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