默认 TextBlock 样式覆盖按钮文本颜色

发布于 2024-10-08 07:33:30 字数 1983 浏览 2 评论 0原文

我的问题发生在 .NET 3.5 SP1 中的 WPF 中,可以描述如下:

我有一个默认的 Style 命中 UI 中的所有 TextBlock 元素。这就是它的样子:

<Style TargetType="{x:Type TextBlock}">
   <Setter Property="TextTrimming" Value="CharacterEllipsis"/>
   <Setter Property="Foreground" Value="Red"/>
</Style>

这对所有 TextBlock 都适用。除此之外,我还有一个 Button 样式,包括一个 ControlTemplate ,看起来像这样(缩短):

<Style x:Key="MyButtonStyle" TargetType="{x:Type Button}" BasedOn="{x:Null}">
   <Setter Property="Foreground" Value="Green"/>
   <Setter Property="Template">
      <Setter.Value>
         <ControlTemplate TargetType="{x:Type Button}">
            <Border x:Name="Border" 
                    Background="{TemplateBinding Background}" 
                    BorderThickness="{TemplateBinding BorderThickness}" 
                    Padding="{TemplateBinding Padding}" 
                    Height="24" 
                    BorderBrush="{TemplateBinding BorderBrush}">
               <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" 
                                 VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                                 TextBlock.Foreground="{TemplateBinding Foreground}"/>
            </Border>
            <ControlTemplate.Triggers>...</ControlTemplate.Triggers>
         </ControlTemplate>
      </Setter.Value>
   </Setter>
</Style>

注意行 TextBlock.Foreground="{TemplateBinding Foreground}"ContentPresenter 中。这应该将按钮文本设置为绿色,事实上它在 Visual Studio 的设计器视图中也是如此。但是当我编译并运行程序时,按钮文本是红色的,文本颜色由默认的 TextBlock 样式设置。我和史努比验证了这一点。

如何防止默认 TextBlock 样式覆盖 TextBlock.Foreground 值? ContentPresenterOverridesDefaultStyle 属性在这种情况下没有帮助。

有什么想法吗?

My problem occurs with WPF in .NET 3.5 SP1 and can be described as follows:

I have a default Style hitting all TextBlock elements in my UI. That is how it looks:

<Style TargetType="{x:Type TextBlock}">
   <Setter Property="TextTrimming" Value="CharacterEllipsis"/>
   <Setter Property="Foreground" Value="Red"/>
</Style>

That works fine for all TextBlocks. In addition to that I have a Button style including a ControlTemplate that looks like this (shortened):

<Style x:Key="MyButtonStyle" TargetType="{x:Type Button}" BasedOn="{x:Null}">
   <Setter Property="Foreground" Value="Green"/>
   <Setter Property="Template">
      <Setter.Value>
         <ControlTemplate TargetType="{x:Type Button}">
            <Border x:Name="Border" 
                    Background="{TemplateBinding Background}" 
                    BorderThickness="{TemplateBinding BorderThickness}" 
                    Padding="{TemplateBinding Padding}" 
                    Height="24" 
                    BorderBrush="{TemplateBinding BorderBrush}">
               <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" 
                                 VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                                 TextBlock.Foreground="{TemplateBinding Foreground}"/>
            </Border>
            <ControlTemplate.Triggers>...</ControlTemplate.Triggers>
         </ControlTemplate>
      </Setter.Value>
   </Setter>
</Style>

Notice the line TextBlock.Foreground="{TemplateBinding Foreground}" in the ContentPresenter. This should set the button text to green and in fact it does in the designer view of Visual Studio. But when I compile and run the program the button text is red, the text color is set by the default TextBlock style. I verified this with Snoop.

How can I prevent the defaultTextBlock style from overriding the TextBlock.Foreground value? The OverridesDefaultStyle property of ContentPresenter doesn't help in this case.

Any idea?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

苦妄 2024-10-15 07:33:30

请参阅此链接的答案 5

发生这种情况是因为
ContentPresenter 创建一个 TextBlock
对于字符串内容,从那时起
TextBlock 不在视觉树中,它
将查找应用程序级别
资源。如果你定义了一种风格
对于应用程序中的文本块
水平,然后它将被应用到
ContentControl 中的这些 TextBlock

解决方法是定义一个
System.String 的 DataTemplate,其中
我们可以显式地使用默认值
TextBlock 显示内容。你
可以将该 DataTemplate 放在
您定义的同一字典
TextBlock 样式,这样
数据模板将应用于
无论 ContentPresenter 受什么影响
你的风格。

尝试将其添加到 ResourceDictionary

<DataTemplate DataType="{x:Type sys:String}">
    <TextBlock Text="{Binding}">
        <TextBlock.Resources> 
            <Style TargetType="{x:Type TextBlock}"/>
        </TextBlock.Resources>
    </TextBlock>
</DataTemplate>

See answer 5 at this link

This happends because the
ContentPresenter creates a TextBlock
for a string content, and since that
TextBlock isn't in the visual tree, it
will lookup to Application level
resource. And if you define a style
for the TextBlock at Application
level, then it will be applied to
these TextBlock within ContentControl

A workaround is to define a
DataTemplate for System.String, where
we can explicitly use a default
TextBlock to display the content. You
can place that DataTemplate in the
same dictionary you define the
TextBlock style so that this
DataTemplate will be applied to
whatever ContentPresenter effected by
your style.

Try adding this to the ResourceDictionary

<DataTemplate DataType="{x:Type sys:String}">
    <TextBlock Text="{Binding}">
        <TextBlock.Resources> 
            <Style TargetType="{x:Type TextBlock}"/>
        </TextBlock.Resources>
    </TextBlock>
</DataTemplate>
追我者格杀勿论 2024-10-15 07:33:30

您最好不要覆盖 TextBlock 的默认样式。到目前为止,我能想到的最好的想法是为 Control 创建一种样式并将其应用到所有顶级窗口。

<!-- App.xaml -->
<Application.Resources>
    <Style x:Key="RedStyle" TargetType="{x:Type Control}">
        <Setter Property="TextTrimming" Value="CharacterEllipsis"/>
        <Setter Property="Foreground" Value="Red"/>
    </Style>
</Application.Resources>

<!-- MainWindow.xaml -->
<Window Style="{StaticResource RedStyle}" ...>
    ...
</Window>

请参阅此处了解更多详细信息:http://www.ikriv.com/dev/dotnet/wpftextstyle/

You are better off not overriding default style for the TextBlock. The best idea I could come up with so far is to create a style for Control and apply it to all top level windows.

<!-- App.xaml -->
<Application.Resources>
    <Style x:Key="RedStyle" TargetType="{x:Type Control}">
        <Setter Property="TextTrimming" Value="CharacterEllipsis"/>
        <Setter Property="Foreground" Value="Red"/>
    </Style>
</Application.Resources>

<!-- MainWindow.xaml -->
<Window Style="{StaticResource RedStyle}" ...>
    ...
</Window>

See here for more details: http://www.ikriv.com/dev/dotnet/wpftextstyle/

苏辞 2024-10-15 07:33:30

关于两个选项:

  1. @Fredrik Hedblad

尝试将其添加到 ResourceDictionary

<DataTemplate DataType="{x:Type sys:String}">
    <TextBlock Text="{Binding}">
        <TextBlock.Resources> 
            <Style TargetType="{x:Type TextBlock}"/>
        </TextBlock.Resources>
    </TextBlock>
</DataTemplate>
  1. @Ivan Krivyakov

您最好不要覆盖 TextBlock 的默认样式。到目前为止,我能想到的最好的想法是为 Control 创建一种样式并将其应用到所有顶级窗口。

我建议采用替代方法并使用附加的依赖属性,例如

namespace AttachedProperties
{
  public static class TextBlockExtensions
  {
    public static bool GetUseAppThemeStyle(DependencyObject obj)
    {
      return (bool)obj.GetValue(UseAppThemeStyleProperty);
    }
    public static void SetUseAppThemeStyle(DependencyObject obj, bool value)
    {
      obj.SetValue(UseAppThemeStyleProperty, value);
    }
    // Using a DependencyProperty as the backing store for UseAppThemeStyle.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty UseAppThemeStyleProperty =
        DependencyProperty.RegisterAttached("UseAppThemeStyle", typeof(bool), typeof(TextBlockExtensions), new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.Inherits));
  }
}

注意:默认情况下您可以将其设置为 true 或 false

然后使用命名空间:

xmlns:attachedProperties="clr-namespace:AttachedProperties"

创建默认样式:

   <Style TargetType="{x:Type TextBlock}" BasedOn="{StaticResource {x:Type TextBlock}}">
    <Style.Triggers>
      <DataTrigger Binding="{Binding Path=(attachedProperties:TextBlockExtensions.UseAppThemeStyle), RelativeSource={RelativeSource Mode=Self}}" Value="True">
        <Setter Property="TextTrimming" Value="CharacterEllipsis"/>
        <Setter Property="Foreground" Value="Red"/>
      </DataTrigger>
    </Style.Triggers>
  </Style>

设置附加属性:

  <Style x:Key="blueButtonStyle" TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Type Button}}">
    <Setter Property="attachedProperties:TextBlockExtensions.UseAppThemeStyle" Value="False" />
    <Setter Property="Foreground" Value="Blue" />
  </Style>

然后,如果您需要获取默认值,则可以在 style:中或直接在按钮上

<Button attachedProperties:TextBlockExtensions.UseAppThemeStyle="False" Foreground="Blue">I'm blue da ba dee da ba die...</Button>

With respect to the 2 options:

  1. @Fredrik Hedblad

Try adding this to the ResourceDictionary

<DataTemplate DataType="{x:Type sys:String}">
    <TextBlock Text="{Binding}">
        <TextBlock.Resources> 
            <Style TargetType="{x:Type TextBlock}"/>
        </TextBlock.Resources>
    </TextBlock>
</DataTemplate>
  1. @Ivan Krivyakov

You are better off not overriding default style for the TextBlock. The best idea I could come up with so far is to create a style for Control and apply it to all top level windows.

I would suggest an alternative approach and use an attached Dependency Property e.g.

namespace AttachedProperties
{
  public static class TextBlockExtensions
  {
    public static bool GetUseAppThemeStyle(DependencyObject obj)
    {
      return (bool)obj.GetValue(UseAppThemeStyleProperty);
    }
    public static void SetUseAppThemeStyle(DependencyObject obj, bool value)
    {
      obj.SetValue(UseAppThemeStyleProperty, value);
    }
    // Using a DependencyProperty as the backing store for UseAppThemeStyle.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty UseAppThemeStyleProperty =
        DependencyProperty.RegisterAttached("UseAppThemeStyle", typeof(bool), typeof(TextBlockExtensions), new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.Inherits));
  }
}

NOTE: You can set it to be true or false by default

Then having the namespace:

xmlns:attachedProperties="clr-namespace:AttachedProperties"

make a default style:

   <Style TargetType="{x:Type TextBlock}" BasedOn="{StaticResource {x:Type TextBlock}}">
    <Style.Triggers>
      <DataTrigger Binding="{Binding Path=(attachedProperties:TextBlockExtensions.UseAppThemeStyle), RelativeSource={RelativeSource Mode=Self}}" Value="True">
        <Setter Property="TextTrimming" Value="CharacterEllipsis"/>
        <Setter Property="Foreground" Value="Red"/>
      </DataTrigger>
    </Style.Triggers>
  </Style>

Then if you need to get the default you can just set the attached property either in a style:

  <Style x:Key="blueButtonStyle" TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Type Button}}">
    <Setter Property="attachedProperties:TextBlockExtensions.UseAppThemeStyle" Value="False" />
    <Setter Property="Foreground" Value="Blue" />
  </Style>

or directly on a button:

<Button attachedProperties:TextBlockExtensions.UseAppThemeStyle="False" Foreground="Blue">I'm blue da ba dee da ba die...</Button>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文