【问题标题】:Setting TabItem foreground color also sets the TabControl foreground color设置 TabItem 前景色也会设置 TabControl 前景色
【发布时间】:2011-03-06 03:16:24
【问题描述】:

我有一个 TabControl 已重新设置样式。 The TabItem has a trigger that is fired when the TabItem is selected that changes the TabItem text to bold and green.我遇到的问题是选项卡内容中的文本也设置为粗体和绿色。

我可以通过将选项卡内容中的所有控件设置为我想要的颜色和字体粗细来解决此问题,但是我必须这样做吗?因此,我必须确保内容区域中的每个文本块都具有将颜色设置为黑色且字体粗细正常的样式。

如何将 TabItem 的 IsSelected 部分设置为显示绿色,但不保留选项卡的内容?

我尝试将 TabControl 的前景设置为黑色,但这不起作用。

您将从下面的代码示例中看到,第一个选项卡上的文本是绿色的,我希望它是黑色的,但没有在选项卡内容中设置每个控件。

下面的代码示例:

    <Grid>
    <Grid.Resources>
        <!-- Tab item -->
        <Style TargetType="{x:Type TabItem}">
            <Setter Property="FontSize" Value="14"/>
            <Setter Property="MinWidth" Value="200"/>
            <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type TabItem}">
                        <Grid>
                            <Border Name="Border" Padding="5,2">
                                <ContentPresenter ContentSource="Header"/>
                            </Border>
                        </Grid>
                        <ControlTemplate.Triggers>
                            <MultiTrigger>
                                <MultiTrigger.Conditions>
                                    <Condition Property="Border.IsMouseOver" Value="True"/>
                                    <Condition Property="IsSelected" Value="False"/>
                                </MultiTrigger.Conditions>
                                <Setter Property="FontWeight" Value="Bold"/>
                                <Setter Property="Foreground" Value="Black"/>
                            </MultiTrigger>

                            <MultiTrigger>
                                <MultiTrigger.Conditions>
                                    <Condition Property="Border.IsMouseOver" Value="False"/>
                                    <Condition Property="IsSelected" Value="False"/>
                                </MultiTrigger.Conditions>
                                <Setter Property="Foreground" Value="Black" />
                            </MultiTrigger>

                            <Trigger Property="IsSelected" Value="True">
                                <Setter Property="Foreground" Value="Green"/>
                                <Setter Property="FontWeight" Value="Bold"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

        <!-- Tab control -->
        <Style  TargetType="{x:Type TabControl}">
            <Setter Property="SelectedIndex" Value="0"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type TabControl}">
                        <Grid>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="200" />
                                <ColumnDefinition Width="*" />
                            </Grid.ColumnDefinitions>
                            <Border Grid.Column="0" Padding="5" Margin="0,0,5,0" CornerRadius="3">
                                <StackPanel Orientation="Vertical">
                                    <ScrollViewer VerticalScrollBarVisibility="Auto" FocusVisualStyle="{x:Null}">
                                        <TabPanel IsItemsHost="True"/>
                                    </ScrollViewer>
                                </StackPanel>
                            </Border>
                            <Border Grid.Column="1" BorderBrush="Black" BorderThickness="0">
                                <ScrollViewer VerticalScrollBarVisibility="Auto" FocusVisualStyle="{x:Null}" Padding="10,0">
                                    <ContentPresenter ContentSource="SelectedContent"/>
                                </ScrollViewer>
                            </Border>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

    </Grid.Resources>

    <TabControl Name="tabControl" TabStripPlacement="Left">
        <!-- First tab item -->
        <TabItem IsSelected="True">
            <TabItem.Header>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="Profile"/>
                </StackPanel>
            </TabItem.Header>
            <TextBlock Text="Page 1 Sample Text with no foreground set." FontSize="30"/>
        </TabItem>

        <!-- Second tab item -->
        <TabItem IsSelected="True">
            <TabItem.Header>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="Profile"/>
                </StackPanel>
            </TabItem.Header>
            <TextBlock Text="Page 2 Sample Text with foreground set manually." FontSize="30" Foreground="Red"/>
        </TabItem>
    </TabControl>
</Grid>

【问题讨论】:

  • 贴出一些代码来找出问题所在!
  • 按要求添加了代码示例。

标签: wpf styling tabitem


【解决方案1】:

我刚刚遇到了同样的问题,在摆弄了一下之后,我想我找到了一个更优雅的解决方案。

我说得更优雅,因为它会使 ContentPresenter 保持完整,并将前景和字体粗细设置器应用于 ContentPresenter 的 TextElement(这基本上是一个附加属性,但这不是重点)。

这种方法的主要优点是,将 ContentPresenter 替换为 TextBlock 会隐式假定标题仅包含文本,这会限制解决方法的可用性并产生不太健壮的代码。将 ContentPresenter 留在原处将允许任何内容,例如图片+文字。

您还需要做的另一件事是为您的 ContentPresenter 命名:

<Setter Property="Template">
     <Setter.Value>
         <ControlTemplate TargetType="{x:Type TabItem}">
             <Grid>
                <Border Name="Border" Padding="5,2">
                   <ContentPresenter x:Name="CP" ContentSource="Header"/>
                </Border>
             </Grid>
             <ControlTemplate.Triggers>
                <MultiTrigger>
                   <MultiTrigger.Conditions>
                      <Condition Property="Border.IsMouseOver" Value="True"/>
                      <Condition Property="IsSelected" Value="False"/>
                   </MultiTrigger.Conditions>
                     <Setter Property="TextElement.FontWeight" TargetName="CP" Value="Bold"/>
                     <Setter Property="TextElement.Foreground" TargetName="CP" Value="Black"/>                                
                </MultiTrigger>...

现在 Foreground 和 FontWeight 将不会被 TabItem 的内容继承(已测试)。

享受:)

【讨论】:

  • 感谢 Gilad,这绝对是一个更好的解决方案。保持 ContentPresenter 不变绝对是要走的路。
  • 我只是把这个例子放在一起。但是 TextElement.ForegroundTextElement.FontWeight 的设置器无效。如果我为网格添加名称grid,然后添加&lt;Setter TargetName="grid" Property="Background" Value="red" /&gt;,它的背景会变成红色。
【解决方案2】:

这已经很老了,但我在寻找类似问题的答案时遇到了它,我发现提供的答案根本没有帮助。 这是我解决此问题的方法。

如果您将 ContentPresenter 更改为您的 tabitem 的控件模板中的 TextBlock,如下所示:

....stuff above here...
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid>
   <Border Name="Border" Padding="5,2">
        <TextBlock x:Name="TabItemContent" Text="{TemplateBinding Header}"/>
   </Border>
</Grid>
... stuff below here....

然后在该控件模板上的触发器中,您在 IsSelected 触发器中指定目标名称..ie。

...stuff above here...
 <Trigger Property="IsSelected" Value="True">
     <Setter Property="Foreground" TargetName="TabItemContent" Value="Green"/>
     <Setter Property="FontWeight" Value="Bold"/>
</Trigger>
... stuff below here ...

应该在选择选项卡时为您提供绿色文本,而不是整个其他时间的绿色,同时将文本拍摄在其余的应用程序中单独。

【讨论】:

    【解决方案3】:

    不幸的是,如果您通过某些触发器在 ContentPresenter 上设置了 Foreground(或 FontWeight),您仍然认为标题将仅包含文本。

    如果您设置 Header="SomeHeaderName"(即仅文本),ContentPresenter 将生成一个 TextBlock 来托管此标题文本; ContentPresenter 将是此 TextBlock 的(逻辑)父级,因此,在 ContentPresenter 上设置的新 Foreground 将由此 TextBlock 继承。这工作正常。

    但是,如果为 Header 分配了一些可视化树,例如带有 Image 和 TextBlock(甚至是单个 TextBlock)的水平 StackPanel,则 StackPanel 的逻辑父级是 TabItem 而不是 ContentPresenter。继承通过逻辑树进行,因此 StackPanel 中的 TextBlock 最终将再次从 TabItem 继承其 Foreground;在 ContentPresenter 上设置的前景对此没有任何影响。

    一种可能的解决方案:一个DataTemplate最终应用到一个ContentPresenter,所以DataTemplate的根的TemplatedParent就是ContentPresenter;并且继承也通过 TemplatedParent-Child 屏障起作用。因此,如果您能够设置 TabItem.HeaderTemplate 而不是 TabItem.Header,那么您可以在 header 的 ContentPresenter 上设置 Foreground,因为 HeaderTemplate 的根将从 ContentPresenter 继承 Foreground。但是,SelectedContent 不会,因为未在 TabItem 上设置 Foreground(并且内容从 TabItem 继承其 Foreground)。

    希望这会有所帮助!

    【讨论】:

      【解决方案4】:

      wpf 中的每个控件都从其父级继承属性。由于 TabItem 的颜色是黑色,它的子元素textblock 也是黑色的。现在,由于您已将整个 TabItem 的前景色更改为绿色,它的所有子项都将继承它。

      在这里你可以将你的 TabItem.Header 或其内容的前景设置为绿色,这样就不会影响 TabItem 中的其他内容。否则,您可以反转解决方案。

      否则试试这个:

      <Window.Resources>
          <DataTemplate x:Key="greenHeaderTemplate">
              <StackPanel Orientation="Horizontal"> 
                  <TextBlock Text="Profile" 
                             FontWeight="Bold" 
                             Foreground="Green"/> 
              </StackPanel> 
          </DataTemplate>
          <DataTemplate x:Key="defaultHeaderTemplate">
              <StackPanel Orientation="Horizontal"> 
                  <TextBlock Text="Profile"/> 
              </StackPanel> 
          </DataTemplate>
      </Window.Resources>
      
      <Trigger Property="IsSelected" Value="True">      
          <Setter Property="HeaderTemplate" 
                  Value="{StaticResource greenHeaderTemplate}"/> 
      </Trigger>
      
      <TabItem IsSelected="True" HeaderTemplate="{StaticResource defaultHeaderTemplate}"> 
          <TextBlock Text="Page 1 Sample Text with no foreground set." FontSize="30"/> 
      </TabItem>
      

      【讨论】:

      • 感谢 Veer,但是如何在不设置内容的情况下设置 tabitem 标题字体的颜色?我了解目标名称,但我尝试了几种不同的方法,但没有任何乐趣。我不断收到一条错误消息,指出无法在 tabitem 标题上设置前景。
      • @Adrian:为标题内的堆栈面板命名并在目标名称中使用它。
      • @Veer。很抱歉很痛苦,但我试过了,但我无法让它工作。也许我做错了(可能!)。你能发布一些代码给我看吗?谢谢
      • @Adrian:StackPanel 没有前景属性。检查我的编辑。
      • @Veer。我很难看到这将如何工作,因为在您的示例代码中,您在触发器的 tabitem 中设置了文本块颜色(按目标名称)。然后,每个 tabitem 需要为每个 textblock 指定一个名称,然后每个 tabitem 都需要一个单独的触发器。我在这里错过了什么吗?我假设我可以设置一个触发器,在需要时更新每个 tabitem。到目前为止,感谢您的帮助。
      【解决方案5】:

      这是一个实用的解决方案,它假定黑色将是 TabItem 中 TextBlocks 等可接受的前景色。

      首先,因为我使用 Canvas 作为我的 TabItem 的主体,所以我制作了这样的自定义样式:

      <Style x:Key="canvasStyle_BlackForeground" TargetType="{x:Type Canvas}">
          <Setter Property="TextElement.Foreground" Value="Black"/>
      </Style>
      

      然后,TabItem(恰好使用 Canvas 作为容器)看起来像这样,其中 TabItem Foreground 设置为 Green,但 Canvas 的样式设置为 Foreground black:

      <TabItem Header="TabItem" Foreground="Green">
                  <Canvas Background="#FFE5E5E5" Style="{StaticResource canvasStyle_BlackForeground}">
                      <TextBlock Canvas.Left="79" Text="This is a TextBlock" Canvas.Top="63"/>
                  </Canvas>
              </TabItem>
      

      如果您使用的是 Grid 而不是 Canvas,它也同样有效。只需将样式的 TargetType 设为 x:Type Grid。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-03-20
        • 2016-03-03
        • 1970-01-01
        • 1970-01-01
        • 2018-04-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多