2

I designed a battery level indicator consisting of a Border inside another Border. The Width of inner Border is Multi-Bound to the outer Border ActualWidth and the battery value itself (from DataContext, ranging from 0.0 to 1.0):

<Border x:Name="BatteryChargeContainer">
    <Border x:Name="BatteryCharge" Margin="1" HorizontalAlignment="Left" Background="Gray">
            <Border.Width>
                <MultiBinding Converter="{StaticResource NormalValueConverter}" FallbackValue="10">
                    <Binding Path="BatteryLevel"/>
                    <Binding Path="ActualWidth" ElementName="BatteryChargeContainer"/>
                </MultiBinding>
            </Border.Width>
        </Border>
</Border>   

==================

class NormalValueConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (values.Any(v => v == null))
            return null;
        var v1 = values[0];
        var v2 = values[1];

        double valor = System.Convert.ToDouble(v1);
        double measure = System.Convert.ToDouble(v2);

        return valor * measure;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Now I want to make something similar for the Background property, with another IMultiValueConverter. The color should be calculated like this:

  • Green if above 0.8;
  • Yellow between 0.6 and 0.8;
  • Orange between 0.3 and 0.6;
  • Red if below 0.3.

These colors are defined as Resources, because I absolutely don't want to declare them in the code, so my question is:

If the colors are defined as resources, and the actual applied color is calculated in the MultiBind Converter, how can I apply color based on the value returned, or else have the MultiConverter assess the available colors and return the selected color itself?

heltonbiker
  • 26,657
  • 28
  • 137
  • 252
  • Is there a reason why you absolutely want to use a MultiValueConverter? Because you could do it with Triggers directly in the xaml. – mgarant May 22 '15 at 18:38
  • @mgarant No, no absolute reason, that's what I figured I should do, but I think you're right, although I'm not sure I know where to start... If you mind to post an answer, I could accept it, surely :) Specifically, I don't know how a trigger would detect if a value is between a given range. – heltonbiker May 22 '15 at 18:42
  • I'll write you an example :) – mgarant May 22 '15 at 18:44

1 Answers1

2

You could use Triggers with a converter. The converter would return true if the value is greater than a given number. Here an example :

<Border x:Name="BatteryChargeContainer">
    <Border x:Name="BatteryCharge" Margin="1" HorizontalAlignment="Left" Background="Gray">
        <Border.Style>
            <Style TargetType="Border">
                <Setter RED.../>
                <Style.Triggers>
                    <DataTrigger Binding="{Binding yourBinding, Converter=theConverter, ConverterParameter=0.3}" Value="true">
                        <Setter ORANGE... />
                    </DataTrigger>
                    <DataTrigger Binding="{Binding yourBinding, Converter=theConverter, ConverterParameter=0.6}" Value="true">
                        <Setter YELLOW... />
                    </DataTrigger>
                    <DataTrigger Binding="{Binding yourBinding, Converter=theConverter, ConverterParameter=0.8}" Value="true">
                        <Setter GREEN... />
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Border.Style>
    </Border>

This should work because all the triggers will be tested in order. So for instance, if you feed the value 0.9, it will return true on every trigger, so it will change the color to orange, then, yellow and then green, so you'll have the green color as a result.

Small but significant detail, in your converter, the parameter you will receive will be a string. You will need to cast it to a float before you test it with the value.

Hope this helps!

mgarant
  • 565
  • 5
  • 18