1

I have a Slider and a TextBlock on my WPF window. The TextBlock needs to change the background, foreground and font size by the value of the slider, by rang.

I built a converter that receives the value of the slider and returns a 0, 1 or 3 for each group.

public class ValueByRange : IValueConverter
{
    public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        double.TryParse(value?.ToString(), out double dValue);

        if (dValue > 80)
            return 2;
        else if (dValue > 50)
            return 1;

        return 0;
    }
    public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return false;
    }
}

My TextBlock looks like this:

<TextBlock Width="30" Text="{Binding ElementName= theSlider, Path=Value}">
        <TextBlock.Style>
            <Style TargetType="TextBlock">
                <Setter Property="Background" Value="Transparent"/>
                <Setter Property="Foreground" Value="Black"/>
                <Setter Property="FontSize" Value="12"/>
                <Setter Property="TextAlignment" Value="Center"/>
                <Style.Triggers>
                    <DataTrigger Binding="{Binding ElementName=theSlider, Path=Value, Converter={StaticResource ValueByRange}}" Value="1">
                        <Setter Property="Background" Value="Yellow"/>
                        <Setter Property="Foreground" Value="Black"/>
                        <Setter Property="FontSize" Value="14"/>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding ElementName=theSlider, Path=Value, Converter={StaticResource ValueByRange}}" Value="2">
                        <Setter Property="Background" Value="Red"/>
                        <Setter Property="Foreground" Value="White"/>
                        <Setter Property="FontSize" Value="16"/>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </TextBlock.Style>
</TextBlock>

It's working fine, but it doesn't feel like the best approach. The converter fires 2 time, each for every DataTrigger. I need more than this 3 ranges and that means the converter will fire more times. It's also not helpful to build a converter for each property, for the same reason.

Is there a way to fire the converter only ones and then check the result (without using code beyond)?

I know this is not the correct syntax, but I mean something like this:

<DataTrigger Binding="{Binding ElementName=theSlider, Path=Value, Converter={StaticResource ValueByRange}}">
    <DataTrigger.Value Value ="1">
        <Setter Property="Background" Value="Yellow" />
        <Setter Property="Foreground" Value="Black" />
        <Setter Property="FontSize" Value="14" />
    </DataTrigger.Value>
    <DataTrigger.Value Value ="2">
        <Setter Property="Background" Value="Red" />
        <Setter Property="Foreground" Value="White" />
        <Setter Property="FontSize" Value="16" />
    </DataTrigger.Value>
</DataTrigger>
Roy Raz
  • 33
  • 1
  • 8
  • 1
    Out of the box you may assign the converted value to the TextBlock's Tag property, and have multiple Triggers on Tag. However, I don't think it is a problem at all that a converter is called multiple times. – Clemens Apr 09 '18 at 06:52
  • How about. Create a base style. Then three more basedon that for the three states. Bind style with a converter returns the appropriate style. – Andy Apr 09 '18 at 08:03

2 Answers2

1

Well, as Clemens said, there's nothing wrong with having a converter called multiple times.

But if you really want to do it, here's an approach that works:

<Grid>
    <Grid.Resources>

        <local:ValueByRange x:Key="ValueByRange" />

        <Style x:Key="TextBlockInLabelStyle" TargetType="TextBlock">
            <Setter Property="Background" Value="Transparent"/>
            <Setter Property="Foreground" Value="Black"/>
            <Setter Property="FontSize" Value="12"/>
            <Setter Property="TextAlignment" Value="Center"/>
            <Style.Triggers>
                <DataTrigger Binding="{Binding}" Value="1">
                    <Setter Property="Background" Value="Yellow"/>
                    <Setter Property="Foreground" Value="Black"/>
                    <Setter Property="FontSize" Value="14"/>
                </DataTrigger>
                <DataTrigger Binding="{Binding}" Value="2">
                    <Setter Property="Background" Value="Red"/>
                    <Setter Property="Foreground" Value="White"/>
                    <Setter Property="FontSize" Value="16"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>

    </Grid.Resources>

    <Grid.RowDefinitions>
        <RowDefinition />
        <RowDefinition />
        <RowDefinition />
        <RowDefinition />
    </Grid.RowDefinitions>

    <Slider Grid.Row="0"
            x:Name="Slider1" 
            Interval="1" 
            Minimum="0" 
            Maximum="100" />

    <Slider Grid.Row="1" 
            x:Name="Slider2" 
            Interval="1" 
            Minimum="0" 
            Maximum="100" />

    <Label Grid.Row="2" Content="{Binding ElementName=Slider1, Path=Value, Converter={StaticResource ValueByRange}}">
        <Label.Resources>
            <Style TargetType="{x:Type TextBlock}" BasedOn="{StaticResource TextBlockInLabelStyle}" />
        </Label.Resources>
    </Label>

    <Label Grid.Row="3" Content="{Binding ElementName=Slider2, Path=Value, Converter={StaticResource ValueByRange}}">
        <Label.Resources>
            <Style TargetType="{x:Type TextBlock}" BasedOn="{StaticResource TextBlockInLabelStyle}" />
        </Label.Resources>
    </Label>
</Grid>
Seb
  • 620
  • 1
  • 5
  • 11
0

I want to make an annotation to the answer above:

This makes use of a very confusing and badly documented feature, which is discussed here and confused the hell out of me when reading the answer.

To be clear: I did NOT understand why the TARGETTYPE here was TextBlock, when we clearly use a Label and the answer is discussed in the link above. It has to do with the fact that the valueconverter returns a DOUBLE, which gets treated with the TEXTBLOCK style while a LABEL style in its place would be ignored. I tested it the hard way...

somedotnetguy
  • 557
  • 2
  • 14