Search code examples
.netwpfwpf-controlstabitem

How to override custom style property to change selected tab's header image source in WPF?


I have recently started to learn WPF, one of the challenges I set up for myself was to mimic a specific UI I found online and see how far I can go.

The current challenge which I have been trying to solve for the past 48 hours to no avail is to change the selected tabitem image when its selection changes.

Like this.

enter image description here

The first should be in the selected tab and the second one when another tab is selected and this will be the case for every tab item where if its not selected its image will not be "lit up".

enter image description here

I have this custom Style for the tab control.

<Style TargetType="TabItem">
    <Setter Property="Template">
        <Setter.Value>
          <ControlTemplate TargetType="TabItem">
              <Grid Name="Panel">
                  <ContentPresenter x:Name="ContentSite" VerticalAlignment="Center" HorizontalAlignment="Center" ContentSource="Header" Margin="10,2"/>
              </Grid>
              <ControlTemplate.Triggers>
                  <Trigger Property="IsSelected" Value="True">
                     <Setter TargetName="Panel" Property="Background" Value="#421d47" />
                  </Trigger>
                  <Trigger Property="IsSelected" Value="False">
                     <Setter TargetName="Panel" Property="Background" Value="Transparent" />
                  </Trigger>
              </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

I tried a few things.

  1. I tried making a new style for every single tab that inherits from the custom style.
<Style x:Name="tab1Image" TargetType="TabItem" BasedOn="{StaticResource {x:Type TabItem}}">
    <Style.Triggers>
         <Trigger Property="IsSelected" Value="True">
            <Setter Property="Image.Source" Value="HomeLitUp.png"/>
         </Trigger>
        <Trigger Property="IsSelected" Value="False">
            <Setter  Property="Image.Source" Value="HomeLitDown.png"/>
        /Trigger>
    </Style.Triggers>
</Style>

it didn't work.

2.I tried assigning the triggers to the tab items when I am making them

<TabItem Width="50" Height="45">
  <TabItem.Style>
    <Style x:Name="tab1Image" TargetType="TabItem" BasedOn="{StaticResource {x:Type TabItem}}">
    <Style.Triggers>
         <Trigger Property="IsSelected" Value="True">
            <Setter Property="Image.Source" Value="HomeLitUp.png"/>
         </Trigger>
        <Trigger Property="IsSelected" Value="False">
            <Setter  Property="Image.Source" Value="HomeLitDown.png"/>
        /Trigger>
      </Style.Triggers>
    </Style>
 </TabItem.Style>
  <TabItem.Header>
   <Image Width="24" Source="HomeLitUp.png"/>
  </TabItem.Header>
</TabItem>

3.I tried adding the image in the custom style then try to override the trigger event

<Grid Name="Panel">
   <ContentPresenter x:Name="ContentSite" VerticalAlignment="Center" HorizontalAlignment="Center" ContentSource="Header" Margin="10,2"/>
   <Image Name="Image" Width="24"></Image>
</Grid>

But it didn't work and I couldn't call "Image" from the style that's basedon it because its out of the scope.

To recap: I am sure there's a solution I am just not getting it, Its easy to change ALL the tabs headers to the two images, I just dont know how to change every tab based on selected true/false to its own two sets of images.

All help will be appreciated as I fried my brain searching and trying for the past 48 hours!


Solution

  • for me the following code works fine:

    <TabItem.Style>
    <Style TargetType="TabItem">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="TabItem">
                    <Grid Name="Panel">
                        <Image Source="/Image/test.png" Height="50"/>
                    </Grid>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsSelected" Value="True">
                            <Setter TargetName="Panel" Property="Background" Value="#421d47" />
                        </Trigger>
                        <Trigger Property="IsSelected" Value="False">
                            <Setter TargetName="Panel" Property="Background" Value="Transparent" />
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    

    it changes the tabcontrols background when the item is selected and deselected. Now you can use a png in front of it where the part you want to color is transparent. So the tabcontrol will be underneath the image and if its background changes the transparent part of the image will let the background of the tabitem shine through and change color. This also removes the need to have two images for selected and unselected state. To get the appearance you want you also need to change the background of the TabControl to the "unselected-purple"

    Use the following image for example: enter image description here

    EDIT: an example using vector this has the adventage that you can set both colors to whatever you like and when you resize the control the corners stay sharp. You can transform any image to XAML/Datapoints for the using InkScape

      <Style TargetType="{x:Type TabItem}" x:Key="tmp">
        <Setter Property="Background" Value="Transparent"/>
        <Setter Property="Foreground" Value="HotPink"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type TabItem}">
                    <Grid>
                        <Border Name="Border" Width="55" Background="{TemplateBinding Background}" CornerRadius="5,5,0,0">
                            <StackPanel Background="Transparent" Margin="0,0,0,2">
                                <Viewbox Height="30" Width="30">
                                    <Path Name="icon" Fill="{TemplateBinding Foreground}" Data="M 4 5 C 2.895 5 2 5.895 2 7 L 4 7 L 4 9 L 2 9 L 2 21 L 4 21 L 4 23 L 2 23 C 2 24.105 2.895 25 4 25 L 26 25 C 27.105 25 28 24.105 28 23 L 26 23 L 26 21 L 28 21 L 28 9 L 26 9 L 26 7 L 28 7 C 28 5.895 27.105 5 26 5 L 4 5 z M 6 7 L 8 7 L 8 9 L 6 9 L 6 7 z M 10 7 L 12 7 L 12 9 L 10 9 L 10 7 z M 14 7 L 16 7 L 16 9 L 14 9 L 14 7 z M 18 7 L 20 7 L 20 9 L 18 9 L 18 7 z M 22 7 L 24 7 L 24 9 L 22 9 L 22 7 z M 17.199219 11.998047 C 18.481219 11.998047 19.400391 12.657359 19.400391 13.568359 C 19.400391 14.168359 18.974937 14.658875 18.335938 14.796875 L 18.335938 14.871094 C 19.112938 15.013094 19.632813 15.588453 19.632812 16.314453 C 19.632812 17.320453 18.651313 17.998047 17.195312 17.998047 C 15.744313 17.999047 14.769531 17.328172 14.769531 16.326172 C 14.769531 15.624172 15.2775 15.053094 16.0625 14.871094 L 16.0625 14.796875 C 15.4235 14.658875 14.998047 14.168359 14.998047 13.568359 C 14.998047 12.657359 15.917219 11.998047 17.199219 11.998047 z M 11.400391 12 C 12.864391 12 13.791016 13.097234 13.791016 14.990234 C 13.791016 16.868234 12.876391 18 11.400391 18 C 9.9213906 18 9.0097656 16.872328 9.0097656 14.986328 C 9.0107656 13.101328 9.9333906 12 11.400391 12 z M 22.943359 12 C 24.407359 12 25.333984 13.097234 25.333984 14.990234 C 25.332984 16.868234 24.418359 18 22.943359 18 C 21.464359 18 20.552734 16.872328 20.552734 14.986328 C 20.552734 13.100328 21.475359 12 22.943359 12 z M 6.1074219 12.154297 L 7.5546875 12.154297 L 7.5546875 17.845703 L 6.1074219 17.845703 L 6.1074219 13.460938 L 6.03125 13.460938 L 4.6582031 14.386719 L 4.6582031 13.140625 L 6.1074219 12.154297 z M 17.199219 12.990234 C 16.745219 12.990234 16.421875 13.293125 16.421875 13.703125 C 16.421875 14.113125 16.750219 14.414063 17.199219 14.414062 C 17.649219 14.414062 17.972656 14.113125 17.972656 13.703125 C 17.972656 13.293125 17.649219 12.990234 17.199219 12.990234 z M 11.400391 13.111328 C 10.848391 13.111328 10.480469 13.735328 10.480469 14.986328 C 10.480469 16.244328 10.848391 16.886719 11.400391 16.886719 C 11.952391 16.886719 12.322266 16.244328 12.322266 14.986328 C 12.322266 13.736328 11.953391 13.111328 11.400391 13.111328 z M 22.943359 13.111328 C 22.391359 13.111328 22.023438 13.735328 22.023438 14.986328 C 22.023438 16.244328 22.391359 16.886719 22.943359 16.886719 C 23.495359 16.886719 23.865234 16.244328 23.865234 14.986328 C 23.865234 13.736328 23.495359 13.111328 22.943359 13.111328 z M 17.199219 15.400391 C 16.659219 15.400391 16.283203 15.727359 16.283203 16.193359 C 16.283203 16.662359 16.659219 16.982422 17.199219 16.982422 C 17.739219 16.982422 18.109375 16.662359 18.109375 16.193359 C 18.109375 15.728359 17.736219 15.400391 17.199219 15.400391 z M 6 21 L 8 21 L 8 23 L 6 23 L 6 21 z M 10 21 L 12 21 L 12 23 L 10 23 L 10 21 z M 14 21 L 16 21 L 16 23 L 14 23 L 14 21 z M 18 21 L 20 21 L 20 23 L 18 23 L 18 21 z M 22 21 L 24 21 L 24 23 L 22 23 L 22 21 z"/>
                                </Viewbox>
                                <ContentPresenter ContentSource="Header" TextBlock.Foreground="{TemplateBinding Foreground}" HorizontalAlignment="Center"/>
                            </StackPanel>
                        </Border>
                        <Rectangle Name="rect" HorizontalAlignment="Stretch" Height="2" Margin="0,-1" VerticalAlignment="Bottom" Fill="Transparent"/>
                    </Grid>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsSelected" Value="True">
                            <Setter Property="Panel.ZIndex" Value="100" />
                            <Setter TargetName="rect" Property="Fill" Value="Lime" />
                            <Setter TargetName="icon" Property="Fill" Value="Lime" />
                            <Setter TargetName="tb" Property="TextBlock.Foreground" Value="Lime" />
                            <Setter Property="Background" Value="White" />
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    

    Result: enter image description here