WPF TabControl - 当TabItem可见性改变时选择不同的选项卡

11

我在一个由ViewModel支持的UserControl上有一个TabControl,其中一个选项卡项的可见性绑定到ViewModel上的一个属性。

<TabControl x:Name="myTabControl">
    <TabItem Header="Tab 1" />
    <TabItem Header="Tab 2" Visibility="{Binding HasData, Converter={StaticResource boolToVisibilityConverter}}"/>
</TabControl>

TabItem的可见性改变时,它会收起(隐藏)TabItem标题,但它仍然显示其内容。
我希望TabControl在其他选项卡被隐藏时自动切换到可见的选项卡,但惊讶地发现它不会自动执行。
通过将事件处理程序附加到TabControlSelectionChanged事件,可以看到TabItem.IsSelected(以及TabControl.SelectedItem)甚至没有受到TabItem.Visibility更改的影响(这是一个错误吗?!)。
我尝试了属性触发器
    <!-- This doesn't compile because of TargetName on the Setter, think you can only use it in Control Templates.
         I don't know how to refer to the parent TabControl from within the TabItem style. -->
    <TabControl.ItemContainerStyle>
        <Style TargetType="{x:Type TabItem}" BasedOn="{StaticResource {x:Type TabItem}}">
            <Style.Triggers>
                <Trigger Property="Visibility" Value="Collapsed">
                    <Setter TargetName="myTabControl" Property="SelectedIndex" Value="0" />
                </Trigger>
            </Style.Triggers>
        </Style>
    </TabControl.ItemContainerStyle>

还有一个数据触发器

    <!-- This doesn't quite work, it affects the Visibility of the TabItem's content too -->
    <TabControl.Style>
        <Style TargetType="{x:Type TabControl}" BasedOn="{StaticResource {x:Type TabControl}}">
            <Style.Triggers>
                <DataTrigger Binding="{Binding Path=SelectedItem.Visibility, ElementName=tabControl}" 
                             Value="Collapsed">
                    <Setter Property="SelectedIndex" Value="0" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </TabControl.Style>

我无法使触发器起作用,并且没有VisibilityChanged事件可以处理,所以我有点困惑并需要帮助。

3个回答

6
TabItem类有一个IsVisibleChanged事件可供使用。

啊,这个可以了!(+1) 不知道为什么我之前没有发现 - 我猜 MSDN 那时可能过滤掉了继承的属性。我会暂时不标记这个作为答案,看看是否有非代码后台的建议,但非常感谢你。 - rikoe

3

将TabControl的SelectedIndex绑定到一个属性上。每当您更改选项卡项的可见性以折叠时,将此属性的值更改为您想要显示的选项卡的索引。


1
你可以将此事件处理程序添加到代码后台。它将首先测试您的控件,并在绑定导致选项卡可见性更改时进行更改。
当然,与其在OnLoaded中执行此操作,将其放入附加属性(AutoSelect?)中完全是有意义的。代码相同。您首先会被调用并附加到IsVisibleChanged事件上。然后唯一的技巧是使用lambda(参数绑定)将TabControl实例传递到事件回调中。我发布此解决方案,因为它更加简短。
private void FrameworkElement_OnLoaded(object sender, RoutedEventArgs e)
{
    var tabControl = (TabControl) sender;
    // register visibility changed to react on changes
    foreach (TabItem item in tabControl.Items)
    {
        item.IsVisibleChanged += (mSender, ev) => item_IsVisibleChanged(mSender, ev, tabControl);
    }
    // if current selected tab is invisible, find and select first visible one.
    if (!((TabItem) tabControl.SelectedItem).IsVisible)
    {
        foreach (TabItem item in tabControl.Items)
        {
            if (item.IsVisible)
            {
                tabControl.SelectedItem = item;
                return;
            }
        }
    }
}

private static void item_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e, TabControl tabControl)
{
    // just became IsVisible = false
    if ((bool)e.NewValue == false)
    {
        if (tabControl == null) return;
        ItemCollection items = tabControl.Items;
        foreach (UIElement item in items)
        {
            if (item.IsVisible)
            {
                tabControl.SelectedItem = item;
                return;
            }
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接