简体   繁体   中英

Style Trigger using tabindex on tabcontrol is not working when itemsource is referenced

I have tabcontrol which uses an observable collection of tabitems as itemsource. I dont want the close button for the first tab alone. So i added the style trigger

<Style TargetType="{x:Type TabItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid Background="White">
<Border Name="Border" BorderBrush="#1b9ed2" Margin="6,0,12,0" Background="White">
<ContentPresenter Height="30" x:Name="ContentSite" ContentSource="Header" VerticalAlignment="Bottom" HorizontalAlignment="Center" Margin="5,15,5,-5">
</ContentPresenter>
</Border>
<Button  Background="Transparent" BorderBrush="Transparent" Name="TabCloseButton" Click="TabCloseButton_Click" HorizontalAlignment="Right" VerticalAlignment="Bottom" ToolTip="Close" HorizontalContentAlignment="Right" Padding="0">
<materialDesign:PackIcon Kind="Close" Foreground="Gray" HorizontalAlignment="Right"/>
</Button>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="TabIndex" Value="0">
<Setter TargetName="TabCloseButton" Property="Visibility" Value="Collapsed"/>
</Trigger>
......
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="FontSize" Value="12"/>
</Style>
</TabControl.Resources>

It works if i just added the items in xaml

<TabControl Name ="ConnectionsTab">
<TabItem Header="...." TabIndex="0"></TabItem>
<TabItem Header="...." TabIndex="1"></TabItem>
</TabControl>

But it doesn't works when I make the itemsource to the tabcontrol

private ObservableCollection<TabItem> tabItems = new ObservableCollection<TabItem>();

inside constructor

tabItems.Add(new TabItem { Header = "Connections", Content = new ResourceAccountDisplayUserControl(response), TabIndex = 0 });
ConnectionsTab.ItemsSource = tabItems;

I don't know why it does not work. Any idea or code to make it work will be helpful.

First of all, TabIndex is not the index if your TabItem inside the TabControl . So, you need a different way to determine the actual tab position.

If your data source implements IList , you could for example write a MultiValueConverter that determines the position of an item within a collection:

public class MyTabItemIndexConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        // TODO: add some validation to avoid unsupported values
        var c = (IList)values[1];
        return c.IndexOf(values[0]);
    }

    public object[] ConvertBack(object values, Type[] targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Side Note: there are probably other ways to determine the index like Determining index of a tabitem .

Then you can use this converter, to store the actual item index somewhere (or use it directly). In this example, I set the TabItem.Tag property to the item index:

<Window.Resources>
    <local:MyTabItemIndexConverter x:Key="tabItemIndexConverter"/>
</Window.Resources>

[...]
<TabControl Name="tabControl1" ItemsSource="{Binding}">
    <TabControl.ItemContainerStyle>
        <Style TargetType="TabItem">
            <Setter Property="Tag">
                <Setter.Value>
                    <MultiBinding Converter="{StaticResource tabItemIndexConverter}">
                        <Binding />
                        <Binding ElementName="tabControl1" Path="ItemsSource" />
                    </MultiBinding>
                </Setter.Value>
            </Setter>
        </Style>
    </TabControl.ItemContainerStyle>

    [...]

</TabControl>

Now with TabItem.Tag you have a property that you can actually use in order to implement your trigger logic.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM