如何覆盖自定义样式 属性 以更改 WPF 中选定选项卡的 header 图像源?

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

我最近开始学习WPF,我为自己设置的挑战之一是模仿我在网上找到的特定UI,看看我能走多远。

我在过去 48 小时内一直试图解决但无济于事的当前挑战是在选择更改时更改选定的 tabitem 图像。

像这样。

第一个应该在选定的选项卡中,第二个应该在另一个选项卡被选中时出现,每个选项卡项目都是这种情况,如果未被选中,其图像将不会 "lit up"。

我有这个选项卡控件的自定义样式。

<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>

我尝试了一些东西。

  1. 我尝试为继承自自定义样式的每个选项卡制作新样式。
<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>

没用。

2.I 在我制作标签项时尝试将触发器分配给它们

<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 尝试在自定义样式中添加图像然后尝试覆盖触发事件

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

但它不起作用,我无法从基于它的样式中调用 "Image",因为它超出了范围。

回顾一下: 我确定有一个解决方案我只是不明白,它很容易将所有选项卡 headers 更改为两个图像,我只是不知道如何根据所选 true/false 将每个选项卡更改为它自己的两组图片。

在过去的 48 小时里,我竭尽全力搜索和尝试,所有帮助将不胜感激!

对我来说,下面的代码工作正常:

<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>

它会在选中和取消选中项目时更改选项卡控件的背景。现在您可以在它前面使用 png,其中您要着色的部分是透明的。所以 tabcontrol 将位于图像下方,如果它的背景发生变化,图像的透明部分将使 tabitem 的背景闪耀并改变颜色。这也消除了为选中和未选中状态设置两个图像的需要。要获得您想要的外观,您还需要将 TabControl 的背景更改为 "unselected-purple"

使用下图为例:

编辑:一个使用矢量的示例,它有一个优点,即您可以将两种颜色设置为您喜欢的任何颜色,并且当您调整控件大小时,角落保持锐利。您可以将任何图像转换为 XAML/Datapoints 以便使用 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>

结果:

所以我想要实现的是看到背景颜色在所有选项卡之间共享并且只有图像是唯一不同的是覆盖该功能并保持其余样式不变,我结束了正在做的是像这样为每个标签制作新样式

<Style x:Key="Tab1Style" 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"/>
         <Image Name="Image" Width="24"/>
     </Grid>
     <ControlTemplate.Triggers>
         <Trigger Property="IsSelected" Value="True">
      <Setter TargetName="Image" Property="Source" Value="HomeLitUp.png"/>
      <Setter TargetName="Panel" Property="Background" Value="#421d47" />
         </Trigger>
         <Trigger Property="IsSelected" Value="False">
      <Setter TargetName="Image" Property="Source" Value="HomeLitDown.png"/>
      <Setter TargetName="Panel" Property="Background" Value="Transparent" />
         </Trigger>
     </ControlTemplate.Triggers>
        </ControlTemplate>
    </Setter.Value>
       </Setter>
   </Style>

然后像这样将每个带有不同图像集的图像分配给每个选项卡。

<TabItem Width="55" Height="45" Style="{StaticResource Tab1Style}"/>
<TabItem Width="55" Height="40" Style="{StaticResource Tab2Style}"/>
<TabItem Width="55" Height="40" Style="{StaticResource Tab3Style}"/>
<TabItem Width="55" Height="40" Style="{StaticResource Tab4Style}"/>
<TabItem Width="55" Height="40" Style="{StaticResource Tab5Style}"/>
<TabItem Width="55" Height="40" Style="{StaticResource Tab6Style}"/>

感谢 Denis Schaf 为选项卡样式提供更清晰的代码。