当源来自 x:Static resx 文件时,在样式中应用 ValueConverter

Apply ValueConverter in style when source comes from x:Static resx file

经过大量搜索和阅读其他问题和帖子后,我无法找到解决方法。注意:我对 WPF 比较陌生(一般不熟悉绑定)。

这是我想要的:

  1. 我想让 window 中的所有 TextBlock 控件以某种方式设置样式。
  2. 该样式还应应用 ValueConverter 以使文本全部大写。
  3. 最后,每个 TextBlock 文本可以来自绑定到视图模型 属性,或者来自绑定到 .resx 文件中的资源字符串

这是我正在玩的内容的摘录:

<!-- in Window resources -->
<help:AllCapsStringConverter x:Key="AllCaps"/>

<Style TargetType="TextBlock">
    <Setter Property="Foreground" Value="Brown" />
    <Setter Property="Text">
        <Setter.Value>
            <Binding>
                <Binding.Converter>
                    <help:AllCapsStringConverter />
                </Binding.Converter>
                <!-- also tried adding:
                <Binding.RelativeSource>
                    <RelativeSource Mode="Self" />
                </Binding.RelativeSource>
                -->
            </Binding>

            <!-- also tried with: 
            <Binding Converter="{StaticResource AllCaps}"/>

            <Binding Path="Text" Converter="{StaticResource AllCaps}"/>
            -->
        </Setter.Value>
    </Setter>
</Style>

<!-- in Window content -->
<TextBlock Text="{x:Static resx:MyResources.MyTitle}" />

这是值转换器,它本身已被证明有效:

class AllCapsStringConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value != null && value is string)
        {
            return ((string)value).ToUpper();
        }
        else
        {
            return value;
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return null;
    }
}

TextBlocks 获得前景色,但没有开始转换。

我能够在本地将转换器应用于单个 TextBlock,但我不想将其应用于 window:

周围的所有 TextBlock
<TextBlock>
    <TextBlock.Text>
        <Binding Source="{x:Static resx:MyResources.MyTitle}"
                 Converter="{StaticResource AllCaps}"/>
    </TextBlock.Text>
</TextBlock>
<!-- which is the same as -->
<TextBlock Style="{StaticResource CustomerInfoTitleStyle}" 
           Text="{Binding Source={x:Static resx:MyResources.MyTitle}, Converter={StaticResource AllCaps}}" />

尝试使用 'Label' 并构建模板,因为 'TextBlock' is not a control.

<Style x:Key="AllCapsLabel" TargetType="{x:Type Label}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Label">
                <TextBlock Foreground="Brown" Text="{Binding Content, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource AllCaps}}" />
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

并这样使用:

<Label Style="{StaticResource AllCapsLabel}" Content="whatever you want" />

如果内容是纯文本(又名 'String'),则文本应始终为大写。

您的转换器无法正常工作,因为您的 TextBlock 正在覆盖 StyleText 属性,其中包括您已添加到绑定中的转换器。

例如:

<Grid.Resources>

    <Style x:Key="MyTextBlockStyle" TargetType="TextBlock">
        <Setter Property="Foreground" Value="Red"/>
        <Setter Property="FontSize" Value="16"/>
        <Setter Property="Text" Value="You won't see this."></Setter>
    </Style>

</Grid.Resources>

<TextBlock Text="You will see this." Style="{StaticResource MyTextBlockStyle}"/>

希望您能从上面看到为什么您的方法不起作用。

更好的解决方案是在 TextBlock 上使用值转换器设置 Text 的值,而不是在 Style 上。

如果您不想这样做,可以使用一种常见的作弊方法来绕过此问题,可以将 TextBlock 的文本 属性 绑定到标签 属性,如下所示:

<Grid.Resources>

    <local:AllCapsConverter x:Key="AllCaps"/>

    <Style x:Key="MyTextBlockStyle" TargetType="TextBlock">
        <Setter Property="Foreground" Value="Red"/>
        <Setter Property="FontSize" Value="16"/>
        <Setter Property="Text" Value="{Binding Tag, RelativeSource={RelativeSource Self}, Converter={StaticResource AllCaps}}"/>
    </Style>

</Grid.Resources>

<TextBlock Tag="You will see this." Style="{StaticResource MyTextBlockStyle}"/>

我非常不喜欢这种方法,但它确实能满足您的需求。我希望您在 TextBlock.

上设置绑定时只使用转换器

lukegv 的方法是另一种选择。但是,不需要使用 Label,因为您正在覆盖模板并且(类似于我上面的示例)您只是绑定到 Content 属性 的 [=20] =].您可以从 ContentControl.

中轻松获得所需的内容

<Grid.Resources>

    <local:AllCapsConverter x:Key="AllCaps"/>

    <Style x:Key="MyContentControl" TargetType="ContentControl">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate>
                    <TextBlock Text="{Binding Content, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource AllCaps}}"/>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

</Grid.Resources>

<ContentControl Style="{StaticResource MyContentControl}" Content="You will see this too!"/>

不过我也不是特别喜欢这个想法,因为您无法访问所有其他 TextBlock 属性。比如我要设置我的TextBlockFontWeight属性那我就被塞满了