Set background color depending on data-bound value
What you probably need is a ValueConverter
. What you are doing now is setting the background color to 'Maybe', 'No' or 'Yes', which clearly isn't a color.
What you need to do is convert that value to a color. You can do it like this.
Create a new class that implements the IValueConverter
interface. It will probably look something like this:
public class YesNoMaybeToColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
switch(value.ToString().ToLower())
{
case "yes":
return Color.Green;
case "no":
return Color.Red;
case "maybe":
return Color.Orange;
}
return Color.Gray;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
// You probably don't need this, this is used to convert the other way around
// so from color to yes no or maybe
throw new NotImplementedException();
}
}
Then add this class as a static resource to your XAML page like this:
<ContentPage.Resources>
<!-- Add this line below -->
<local:YesNoToBooleanConverter x:Key="YesNoMaybeToColorConverter" />
<!-- You can remove the underneath -->
<!--<ResourceDictionary>
<Color x:Key="Maybe">#ffddbc21</Color>
<Color x:Key="Yes">#3CB371</Color>
<Color x:Key="No">#B22222</Color>
<Color x:Key="Depends">#ffd78800</Color>
</ResourceDictionary>-->
</ContentPage.Resources>
Now in your binding you have to tell him what converter to use. Do it like this:
<Label Text="{Binding Result}" HorizontalOptions="FillAndExpand" BackgroundColor="{Binding Result, Converter={StaticResource YesNoMaybeToColorConverter}}" />
It should now see the value in the Result
field, put it through the converter you have defined and return the color that you corresponded to that value.
For a pure XAML way of achieving this without much overhead, you can use a DataTrigger
. Note that you can add as many setters per trigger as needed, making this slightly more flexible than the previously suggested solutions, it's also keeping view logic in the view where it should be.
<Label Text="{Binding Result}" HorizontalOptions="FillAndExpand">
<Label.Triggers>
<DataTrigger TargetType="Label" Binding="{Binding Result}" Value="Yes">
<Setter Property="BackgroundColor" Value="#3CB371" />
</DataTrigger>
<DataTrigger TargetType="Label" Binding="{Binding Result}" Value="No">
<Setter Property="BackgroundColor" Value="#B22222" />
</DataTrigger>
<DataTrigger TargetType="Label" Binding="{Binding Result}" Value="Maybe">
<Setter Property="BackgroundColor" Value="#ddbc21" />
</DataTrigger>
<DataTrigger TargetType="Label" Binding="{Binding Result}" Value="Depends">
<Setter Property="BackgroundColor" Value="#d78800" />
</DataTrigger>
</Label.Triggers>
</Label>
Note that you could probably cut out one of the triggers by setting the BackgroundColor
property to a sensible default (likely "Depends" in this case).
I found 2 another options for managing this, because sometimes we need to change not only color but font and other values. At first you need to add name to your control like this:
<Label x:Name="MyLabel" Text="{Binding Result}" HorizontalOptions="FillAndExpand"/>
1. You can set color and other properties in code behind like this, this way needs some time for updating, so it's not the best choice, when Text property was just updated.
protected override void OnAppearing()
{
if (this.MyLabel.Text.Contains("yes")
{
this.MyLabel.TextColor = Color.FromHex("#98ee99");
}
else
{
this.MyLabel.TextColor = Color.FromHex("#ff867c");
}
}
2. Another way is using Prism EventAggregator, I guess in Xamarin.Forms it is Messaging Center. Here is one good example with Prism.
In this case you should send Event with your value from whatever place in your project, for example when it's should be already updated.
_evenAggregator.GetEvent<MyEvent>().Publish(Result);
Then you should subscribe the Event in place where you need to receive fresh value. In this case it should be OnAppearing method in code behind class.
void UpdateColor(string result)
{
if(result.Contains("yes")
{
this.MyLabel.TextColor = Color.FromHex("#98ee99");
}
else
{
this.MyLabel.TextColor = Color.FromHex("#ff867c");
}
}
protected override void OnAppearing()
{
base.OnAppearing();
_eventAggregator.GetEvent<MyEvent>().Subscribe(UpdateColor);
}