I have been using MvvmCross for years, and I still come across little areas that I didn't know existed. Recently I came across this problem:

I have a view that I want to change the background colour based on the count of a list and a boolean warning flag, the logic for the background is as follows:

  • When the count = 0 it should be grey
  • When the count > 0 it should be blue
  • When the warning flag equals true then it should be red, this should override the first two rules

At first, I thought I could make the count -1 when the warning flag is true, but that is changing the ViewModel data to suit the view, in other words 🀒.

Then thought I could create a state property working out what state the background is in, but that is adding more properties to the ViewModel that I don't need, I have the data.

I then thought I had used Value Converters before; if I could somehow pass the two properties to the converter, then it could work it out. Quickly I realised I had hit this problem before and some of the suggest solutions are to pass the whole ViewModel... πŸ˜’ I'm not too fond of that solution as it feels like a hack. I realised this is similar to the problem of wanting to have two bindable properties in a converter.

In my futile search for two bindable properties in a converter, I came across Value combiners, which have various uses; numeric operations, formating and boolean operations. You can check the list of default combiners here. I then thought if I could use the MvxIfValueCombiner on the warning flag bool, and when true pass the warning flag and when false pass the count. Then I am only passing one bound property into the converter. Hazzah!!! One problem down! The next issue was making a converter that would accept a bool or an int, which I accomplish by using the interface 'IValueConverter'.

So this is what the binding looks like:

set.Bind(ViewWithChangingBackground)
    .For(v => v.BackgroundColor)
    .ByCombining(new MvxIfValueCombiner(),
        vm => vm.HasWarning, 
        vm => vm.HasWarning, vm => vm.Count)
    .WithConversion(new BackgroundColorValueConverter());

and the converter looks like this:

public class BackgroundColorValueConverter : IMvxValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return value switch
        {
            bool warning when warning => Theme.Color.Red,
            int count when count > 0 => Theme.Color.SkyBlue,
            _ => Theme.Color.LightGrey,
        };
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

I thought this was quite an elegant solution to my problem. Let me know what you think!