【问题标题】:Is there a workaround for this tabcontrol/tabitem bug这个 tabcontrol/tabitem 错误是否有解决方法
【发布时间】:2011-11-03 18:55:00
【问题描述】:

除非我弄错了(我希望是这样),否则TabControl 存在与TabItems 的可见性相关的错误。 这是重现该错误的 XAML。

<UserControl x:Class="TabControl_bug.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">
    <Grid x:Name="LayoutRoot" Background="White">
        <sdk:TabControl>
            <sdk:TabItem Header="tabItem1"  Visibility="Collapsed">
                <TextBlock Text="TabItem1 which should not be visible" VerticalAlignment="Center" HorizontalAlignment="Center"/>
            </sdk:TabItem>
            <sdk:TabItem Header="tabItem2">
                <TextBlock Text="TabItem2 which should be visible" VerticalAlignment="Center" HorizontalAlignment="Center"/>
            </sdk:TabItem>
        </sdk:TabControl>
    </Grid>
</UserControl>

当你运行这段代码时,你会看到 TabItem2 没有被“选中”,所以显示的内容是

不应显示的 TabItem 1

一旦你选择了选项卡,那么当然会显示TabItem2的内容,并且无法返回到tabItem1,但问题在于初始显示。

如果我将 SelectedIndex 属性设置为 1,则会显示正确的内容。但是我不知道在 XAML 中应该首先选择哪个选项卡。

对于这个问题有哪些可能的解决方法。理想情况下,tabcontrol 已经预先选择了它的第一个可见的 tabitem。

【问题讨论】:

  • 我们可以清理一下吗?我们知道默认选中项是第一项(索引 0)。让我们暂时假设没有任何选项卡项被折叠。对于“应该首先选择哪个选项卡”,我们是否仍然一无所知?还是默认正确?如果默认值是正确的,那么如果默认值实际上是折叠的,那么应该选择下一个可用的选项卡。由于您可以在 Xaml 中看到折叠的内容,因此我们可以看到 SelectedIndex 应该是什么。
  • 如果我们不知道将要折叠的内容必须是代码的结果,那么该代码不应该设置 SelectedIndex 吗?
  • 解决方法:订阅 TabControl 的 Loaded 事件,找到第一个可见的 TabItem 并将其标记为选中。
  • @Nestor:听起来像是对我的回答,你为什么要发表评论?
  • NestorArturo,把它作为答案,我会接受它,因为这就是我最终要做的。

标签: silverlight silverlight-4.0


【解决方案1】:

我找到了下一个解决方案。对于 MainPage 构造函数中的示例:

tabControl.SetValue(TabControl.SelectedContentProperty, null);

您也可以在 Loaded 事件中执行此操作。

很遗憾,TabControl.SelectedContent 属性没有公共设置器,因此您可以直接设置 SelectedContentProperty。

编辑:

此功能的行为:

public class UnselectContentBehavior : Behavior<TabControl>
{
        protected override void OnAttached()
        {
            base.OnAttached();
            AssociatedObject.Loaded += OnLoaded;
        }

        private void OnLoaded(object sender, RoutedEventArgs e)
        {
            AssociatedObject.SetValue(TabControl.SelectedContentProperty, null);
        }

        protected override void OnDetaching()
        {
            base.OnDetaching();
            AssociatedObject.Loaded -= OnLoaded;
        }
 }

使用示例:

       <sdk:TabControl x:Name="tabControl">
            <sdk:TabItem Header="tabItem1"  Visibility="Collapsed">
                <TextBlock Text="TabItem1 which should not be visible" VerticalAlignment="Center" HorizontalAlignment="Center"/>
            </sdk:TabItem>
            <sdk:TabItem Header="tabItem2">
                <TextBlock Text="TabItem2 which should be visible" VerticalAlignment="Center" HorizontalAlignment="Center"/>
            </sdk:TabItem>

            <i:Interaction.Behaviors>
                <b:UnselectContentBehavior/>
            </i:Interaction.Behaviors>
        </sdk:TabControl> 

【讨论】:

    【解决方案2】:

    我在尝试解决here 描述的问题时遇到了这个问题。我找到了一个涵盖这两种情况的合理解决方案。附加属性“SelectOnlyVisibleTabs”在 TabControl 中设置为 true 以更正其行为。要在运行时更改 TabItems 的可见性,附加的“Visibility”属性还可以防止 TabControl 的不当行为。完整的解决方案:

    public static class TabControlExtensions
    {
        /// <summary>
        /// Use this property on a TabControl to correct the behavior
        /// of selecting Collapsed TabItems.
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static bool GetSelectOnlyVisibleTabs(DependencyObject obj)
        {
            return (bool)obj.GetValue(SelectOnlyVisibleTabsProperty);
        }
        public static void SetSelectOnlyVisibleTabs(DependencyObject obj, bool value)
        {
            obj.SetValue(SelectOnlyVisibleTabsProperty, value);
        }
        public static readonly DependencyProperty SelectOnlyVisibleTabsProperty =
            DependencyProperty.RegisterAttached("SelectOnlyVisibleTabs", typeof(bool), typeof(TabControlExtensions), new PropertyMetadata(false, SelectOnlyVisibleTabsChanged));
        public static void SelectOnlyVisibleTabsChanged(object sender, DependencyPropertyChangedEventArgs args)
        {
            var tabControl = sender as TabControl;
            if (tabControl == null) return;
    
            if ((bool)args.NewValue)
            {
                tabControl.SelectionChanged += TabControl_SelectionChanged;
                CorrectSelection(tabControl);
            }
            else
            {
                tabControl.SelectionChanged -= TabControl_SelectionChanged;
            }
        }
    
        private static void TabControl_SelectionChanged(object sender, SelectionChangedEventArgs args)
        {
            var tabControl = sender as TabControl;
            if (tabControl == null) return;
    
            CorrectSelection(tabControl);
        }
    
        public static void CorrectSelection(TabControl tabControl)
        {
            var selected = tabControl.SelectedItem as UIElement;
            if (selected == null) return;
    
            // If the selected element is not suposed to be visible,
            // selects the next visible element
            if (selected.Visibility == System.Windows.Visibility.Collapsed)
                tabControl.SelectedItem = tabControl.Items.OfType<UIElement>()
                    .Where(e => e.Visibility == System.Windows.Visibility.Visible)
                    .FirstOrDefault();
        }
    }
    
    public static class TabItemExtensions
    {
        /// <summary>
        /// Use this property in a TabItem instead of the original "Visibility" to 
        /// correct the behavior of a TabControl when a TabItem's Visibility changes.
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static Visibility GetVisibility(DependencyObject obj)
        {
            return (Visibility)obj.GetValue(VisibilityProperty);
        }
        public static void SetVisibility(DependencyObject obj, Visibility value)
        {
            obj.SetValue(VisibilityProperty, value);
        }
        public static readonly DependencyProperty VisibilityProperty =
            DependencyProperty.RegisterAttached("Visibility", typeof(Visibility), typeof(TabItemExtensions), new PropertyMetadata(Visibility.Visible, VisibilityChanged));
    
        public static void VisibilityChanged(object sender, DependencyPropertyChangedEventArgs args)
        {
            var tabItem = sender as TabItem;
            if (tabItem == null) return;
    
            var visibility = (Visibility)args.NewValue;
            if (tabItem.Visibility == visibility) return;
    
            tabItem.Visibility = visibility;
            if (visibility == Visibility.Visible) return;
    
            // Finds the tab's parent tabcontrol and corrects the selected item, 
            // if necessary.
            var tabControl = tabItem.Ancestors().OfType<TabControl>().FirstOrDefault();
            if (tabControl == null) return;
    
            TabControlExtensions.CorrectSelection(tabControl);
        }
    }
    

    用法:

    <sdk:TabControl local:TabControlExtensions.SelectOnlyVisibleTabs="True">
        <sdk:TabItem Header="tabItem1" Visibility="Collapsed">
            <TextBlock HorizontalAlignment="Center"
                       VerticalAlignment="Center"
                       Text="TabItem1 which should not be visible (1)" />
        </sdk:TabItem>
        <sdk:TabItem Header="tabItem2">
            <TextBlock HorizontalAlignment="Center"
                       VerticalAlignment="Center"
                       Text="TabItem2 which should be visible (2)" />
        </sdk:TabItem>
        <sdk:TabItem DataContext="{Binding ViewModel}"
                     Header="tabItem3"
                     local:TabItemExtensions.Visibility="{Binding MyProperty,
                                                                 Converter={StaticResource BoolToVisibilityConverter}}">
            <TextBlock HorizontalAlignment="Center"
                       VerticalAlignment="Center"
                       Text="TabItem with binded Visibility (3)" />
        </sdk:TabItem>
    </sdk:TabControl>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-29
      • 2018-06-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-22
      相关资源
      最近更新 更多