Есть ли обходной путь для этой ошибки tabcontrol/tabitem
Если я не ошибаюсь (что я надеюсь, что есть), есть ошибка с 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 не "выбран", и поэтому отображаемый контент
TabItem1, который не должен быть виден
После выбора вкладки, конечно, отображается содержимое TabItem2, и нет возможности вернуться к tabItem1, но проблема заключается в начальном отображении.
Если я установлю SelectedIndex
свойство до 1 отображается правильный контент. Однако в XAML я не знаю, какую из вкладок следует выбрать в первую очередь.
Какие обходные пути возможны для этой проблемы. В идеале tabcontrol предварительно выбрал свой первый видимый tabitem.
2 ответа
Я нашел следующее решение. Для вашего примера в конструкторе 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>
Я сталкивался с этим вопросом, пытаясь решить проблему, описанную здесь. Я нашел разумное решение, которое охватывает оба случая. Присоединенное свойство "SelectOnlyVisibleTabs" установлено в true в TabControl, чтобы исправить его поведение. Чтобы изменить видимость 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>