选项卡控制器中的两个选定选项卡

Posted

技术标签:

【中文标题】选项卡控制器中的两个选定选项卡【英文标题】:Two selected tabs in tabcontroller 【发布时间】:2014-09-23 14:32:09 【问题描述】:

我的 TabControl 存在问题,我在其中管理(在某些特殊情况下)选择两个选项卡标题(只有一个显示 afaik 的主体),并且我无法更改选定的选项卡。

选定的选项卡具有粗体标题文本。

在这张图片中,“Ämnesinformation”和“R43”都被选中了。

我的申请结构如下:

我有一些看法:

MainView:主视图,包含TabControl,它只包含图像中的一项。 SubstanceTabsView: MainView 中的每个选项卡都有一个。 SubstanceView 和ClassificationView:第一个用于“Ämnesinformation”,每种物质只有一个。第二个可以有多个实例,例如“R43”、“R12”等。

我也有一些 viewModel:

MainViewModel: MainView 的 VM。 SubstanceTabsViewModel: SubstanceTabsView 的 VM,包含一组 IViewModel SubstanceViewModel、ClassificationViewModel:都实现了IViewModel,都是SubstanceView和ClassificationView的VM

一些相关的xaml代码:

这是 MainView.xaml 中的选项卡控件

<TabControl SelectedItem="Binding Path=SelectedTab" ItemsSource="Binding Path=Tabs" >
        <TabControl.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="Binding Header" >
                    </TextBlock>
                    <local:CrossButton Margin="3" Padding="0" Width="12" Command="Binding CloseCommand"/>
                </StackPanel>
            </DataTemplate>
        </TabControl.ItemTemplate>
        <TabControl.Resources>
            <Style TargetType="x:Type TabItem">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="x:Type TabItem">
                            <Grid>
                                <Border 
                                Name="Border"
                                Margin="0,0,-4,0" 
                                Background="Binding Path=HeaderBackground"
                                BorderBrush="#A0A0A0" 
                                BorderThickness="1,1,1,1" 
                                CornerRadius="3,10,0,0" >
                                    <ContentPresenter x:Name="ContentSite"
                                  VerticalAlignment="Center"
                                  HorizontalAlignment="Center"
                                  ContentSource="Header"
                                  Margin="12,2,12,2"
                                  RecognizesAccessKey="True"/>
                                </Border>
                            </Grid>
                            <ControlTemplate.Triggers>
                                <Trigger Property="IsSelected" Value="True">
                                    <Setter Property="FontWeight" Value="Bold" />
                                    <Setter Property="Panel.ZIndex" Value="100" />
                                    <Setter TargetName="Border" Property="Background" Value="Binding HeaderBackground" />
                                    <Setter TargetName="Border" Property="BorderThickness" Value="1,1,1,0" />
                                </Trigger>
                                <Trigger Property="IsEnabled" Value="False">
                                    <Setter TargetName="Border" Property="Background" Value="Yellow" />
                                    <Setter TargetName="Border" Property="BorderBrush" Value="Black" />
                                    <Setter TargetName="Border" Property="BorderThickness" Value="1,1,1,0" />
                                    <Setter Property="Foreground" Value="Green" />
                                </Trigger>
                            </ControlTemplate.Triggers>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
            <DataTemplate DataType="x:Type localViewModels:SubstanceTabsViewModel">
                <localViews:SubstanceTabsView />
            </DataTemplate>
            </TabControl.Resources>

    </TabControl>

这是我在 SubstanceTabsView.xaml 中控制不同视图和视图模型之间连接的方法

<TabControl SelectedItem="Binding Path=SelectedTab"  ItemsSource="Binding Path=Tabs">
        <TabControl.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="Binding Header" />
                    <local:CrossButton Margin="3" Padding="0" Width="12" Command="Binding CloseCommand"/>
                </StackPanel>
            </DataTemplate>
        </TabControl.ItemTemplate>
        <TabControl.Resources>
            <DataTemplate DataType="x:Type localViewModels:ClassificationViewModel">
                <localViews:ClassificationView />
            </DataTemplate>
            <DataTemplate DataType="x:Type localViewModels:SubstanceViewModel">
                <localViews:SubstanceView />
            </DataTemplate>
        </TabControl.Resources>
    </TabControl>

这是控制二级标签的 SubstanceTabsViewModel.cs 的代码,selectedTab 的设置器控制一些逻辑,询问用户如何从未保存的标签更改:

private IViewModel selectedTab;
    public IViewModel SelectedTab
    
        get
        
            return selectedTab;
        
        set
        
            MessageBoxResult rsltMessageBox = MessageBoxResult.Yes;
            if (selectedTab != null && selectedTab.SaveNeeded() && selectedTab.Id != 0 && value != null && selectedTab is ClassificationViewModel)
            
                rsltMessageBox = notifyUserService.Ask("Bedömning är ändrad men ej sparad vill du verkligen lämna fliken?", "Bedömning ändrad");
            
            if (rsltMessageBox == MessageBoxResult.Yes)
            
                selectedTab = value;
            
            OnPropertyChanged("SelectedTab");

        
    

    private ObservableCollection<IViewModel> tabs;
    public ObservableCollection<IViewModel> Tabs
    
        get
        
            return tabs;
        
        set
        
            tabs = value;
            OnPropertyChanged("Tabs");
        
    

我的调查导致了一些事情:如果我不执行 notifyUserService 调用(导致 messagebox.show()),没有问题,只选择了一个选项卡。如果我查看 TabControl 的 SelectedItem,它只是一个项目,它“应该”在我的情况下。

【问题讨论】:

我使用以下示例代码观察到类似的行为:Why do WPF tabs become "unresponsive" when Dispatcher.Invoke() is called? 【参考方案1】:

我终于找到其他人有类似的问题,如here**所述,“显示消息框会导致嵌套消息泵;这意味着几乎所有处理都恢复了。当然,我们正在尝试中更改选定的项目,因此这可能会导致各种乱序或重入问题。这类问题很难修复,我们将无法在下一个版本中修复它。所以问题在于在 selectedItem 设置器中使用 MessageBox:es。

我想在这种情况下使用一些巧妙的解决方法是合适的解决方案。

** 2022 年 3 月更新

原帖引用的 URL 不再有效。现在可以在这里找到内容:WPF TabControl bug

【讨论】:

链接中建议的附加行为在我的情况下不起作用。还是有同样的问题:(

以上是关于选项卡控制器中的两个选定选项卡的主要内容,如果未能解决你的问题,请参考以下文章

iPhone TabBarController - 以编程方式设置选定的选项卡

在点击事件上更改选定的选项卡

从模态视图控制器 ios7 更改选项卡栏应用程序的选定索引

选项卡栏为更多选项卡选择的索引

两个浏览器选项卡中的相同 Vue.js 组件使 <select> 镜像其选定值

popBack 到选定选项卡的第一个视图控制器