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



我研究这个问题已经有一段时间了,但只找到了部分解决方案。

我试图设置一个TabControl,这样我就可以在某些情况下阻止用户更改当前选择的选项卡。当阻止用户更改当前选择的选项卡时,将向他们显示一个对话框。

我已经阅读了以下文件:

  • WPF -当ItemsSource改变时重置列表框滚动位置
  • http://wizardsofsmart.net/uncategorized/itemssourcechanged-event-using-attached-dependency-properties/
  • http://joshsmithonwpf.wordpress.com/2009/09/04/how-to-prevent-a-tabitem-from-being-selected/
  • http://social.expression.microsoft.com/Forums/en-US/wpf/thread/f7b46018-1e97-4bbe-ada8-49b75dbc1da2/

我已经实现了第三个链接中指出的解决方案(尽管上面所有的都创建了下面所见的相同错误)。但是

如果用户做了以下事情,事情就会彻底混乱:

  • 尝试在不允许的情况下更改选项卡。消息框弹出错误。
  • 用户点击"确定",返回原窗口。
  • 用户再次尝试更改选项卡。
  • 如果用户最小化窗口,然后再次最大化窗口,那么应该早些出现的消息框就会出现。
  • 用户点击"OK",返回到原窗口…,但选项卡已更改为他们之前选择的选项卡,即使他们不应该能够更改选项卡

这显然不是的理想行为。为什么没有出现第二次消息框,为什么选项卡改变时,它应该被禁止这样做?

如果我删除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结构支持窗口。

正如您注意到的,问题出在事件处理程序中的MessageBox。焦点将改变到MessageBox,你可以得到各种不希望的效果。我也有自己的问题。

这里有几个关于同一主题的问题
WPF:消息框打破PreviewMouseDown吗?
当消息框出现时,Wpf停止路由事件?

如果你必须向用户显示消息,那么另一种方法可能是创建一个新的Window,你的风格像MessageBox,然后调用Show (不是 ShowDialog)在它的事件处理程序内。

我知道这篇文章有点老了,但是我有一个非常简单的方法来完成这个:

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

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

[TabControl SelectionChanged Strange Behaviour?])

请忽略格式不佳的问题和答案。但是,正如在答案中提到的,将其放在调度程序中并在设置索引后聚焦所选选项卡,为我解决了这个问题。

你错过了一个简单的技巧。只需将标签页头设置为focusable=False。

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

你可以把这个属性绑定到你的视图模型。

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

最新更新