Search code examples
wpfxamlivalueconverterwpf-style

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


After quite some search and reading other questions & posts, I was not able to find how to solve this. Note: I'm relatively new to WPF (not to binding in general).

Here's what I'm after:

  1. I'd like to have all TextBlock controls in a window to be styled in some way.
  2. The style should also apply a ValueConverter to make text all uppercase.
  3. Finally, each TextBlock Text could come either from binding to a view-model property, or from binding to a resource string from a .resx file

Here's an excerpt of what I'm playing with:

<!-- 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}" />

Here's the value converter, which on its own has proved to be working:

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 get the foreground color, but no conversion kicks in.

I was able to apply the converter locally to the single TextBlock, but I don't want to apply that to all TextBlocks around the window:

<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}}" />

Solution

  • Try to use a 'Label' and build a template, because a '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>
    

    And use it this way:

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

    If the content is plain text (aka a 'String'), the text should always be uppercase.