我有TabControl,它被用作我的应用程序的一个主要元素:

每个选项卡内容都有一个标题(与菜单名称重复)、分隔符和内容。必须与此视图相对应的XAML代码应该如下所示:
<TabControl Style="{StaticResource MyCustomStyle}">
<TabItem Header="Menu 1">
<TabItem.Content>
...
</TabItem.Content>
</TabItem>
<TabItem Header="Menu 2">
<TabItem.Content>
<TextBlock>Content</TextBlock>
</TabItem.Content>
</TabItem>
...
</TabControl>为了避免重复部分代码,我决定以自定义样式设置视图。MyCustomStyle用于此:
<Style x:Key="MyCustomStyle" TargetType="{x:Type TabControl}">
<Style.Resources>
<Style TargetType="{x:Type TabItem}">
<Setter Property="Padding" Value="10"/>
<Setter Property="Width" Value="120"/>
<Setter Property="Content">
<Setter.Value>
<StackPanel Margin="10">
<Label FontSize="20" Content="..."/>
<Separator/>
<ContentPresenter ContentSource="..."/>
</StackPanel>
</Setter.Value>
</Setter>
</Style>
</Style.Resources>
<Setter Property="TabStripPlacement" Value="Left"/>
</Style>唯一的问题是修改内容。标签不想将值绑定到TabItem的头部。
我试图为此使用RelativeSource,但这是行不通的:
<Label FontSize="20" Content="{Binding RelativeSource={RelativeSource AncestorType={x:Type TabItem}}, Path=Header}"/>发布于 2016-11-01 18:26:32
如果我理解正确的话,你就很接近了--你只是想给它一个ContentTemplate,而不是用样式设置Content:
<Style x:Key="MyCustomStyle" TargetType="{x:Type TabControl}">
<Style.Resources>
<Style TargetType="{x:Type TabItem}">
<Setter Property="Padding" Value="10"/>
<Setter Property="Width" Value="120"/>
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Margin="10">
<Label FontSize="20" Content="..."/>
<Separator/>
<ContentControl
Content="{Binding}"
/>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</Style.Resources>
<Setter Property="TabStripPlacement" Value="Left"/>
</Style>现在,关于标签内容。您不能通过RelativeSource AncestorType获得这一点,因为TabItem不在可视树中:如果您编写了一个VisualTreeHelper.GetParent()循环,您会发现父链碰到了一些随机的东西,比如网格之类的东西,然后突然出现在TabControl上。
所以我们要做的是写一个多值转换器。我们给它DataContext表示DataTemplate --这是TabItem it的Content -和TabControl。然后,我们通过TabControl的Items查找具有相同Content的TabItem。
我尝试作为一个常规的值转换器,只从Label传入Label,在转换器内的可视树中遍历以找到TabControl,并使用转换器内的Label's DataContext来识别我想要的TabItem。这是因为(我认为)虚拟化没有起作用:DataTemplate被实例化一次,这些控件被重用。因为每次{RelativeSource Self}的值都是相同的,而且我没有告诉Binding关于DataContext的任何事情,所以值转换器只对被选中的第一个TabItem调用。多值转换器通过显式绑定到. ( DataContext )来解决这个问题.
如果使用ItemsSource填充TabControl,这种情况就会中断。事实上,如果您在TabControl中填充了TabItems以外的任何内容,它就会中断,就像您做的那样。但是,您不可能以其他方式设置它们的Header属性,如果您使用的是ItemsSource,那么您将有各种各样的好东西要绑定,而且您也不会考虑像这样的疯狂的权宜之计。
TabItemHeaderConverter.cs
public class TabItemHeaderConverter : IMultiValueConverter
{
// This is pretty awful, but nobody promised life would be perfect.
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
var tc = values[0] as TabControl;
var tabItemContent = values[1];
var tabItem = tc.Items.Cast<TabItem>().FirstOrDefault(ti => ti.Content == tabItemContent);
if (null != tabItem)
{
return tabItem.Header;
}
return "Unknown";
}
public object[] ConvertBack(object value, Type[] targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}新的XAML:
<Style x:Key="MyCustomStyle" TargetType="{x:Type TabControl}">
<Style.Resources>
<local:TabItemHeaderConverter x:Key="TabItemHeaderConverter" />
<Style TargetType="{x:Type TabItem}">
<Setter Property="Padding" Value="10"/>
<Setter Property="Width" Value="120"/>
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Margin="10">
<Label
FontSize="20"
>
<Label.Content>
<MultiBinding Converter="{StaticResource TabItemHeaderConverter}">
<Binding RelativeSource="{RelativeSource AncestorType=TabControl}" />
<Binding Path="." />
</MultiBinding>
</Label.Content>
</Label>
<Separator />
<ContentControl
Content="{Binding}"
/>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</Style.Resources>
<Setter Property="TabStripPlacement" Value="Left"/>
</Style>https://stackoverflow.com/questions/40366090
复制相似问题