Set LinearLayout background color via boolean value
Asked Answered
M

3

8

I'm trying to use an MvxValueConverter to set the background color of a LinearLayout based on a boolean value. The converter looks like this:

public class BackgroundColorValueConverter : MvxValueConverter<bool, MvxColor>
{
    private static readonly MvxColor TrueBGColor = new MvxColor(0xDB, 0xFF, 0xCE);
    private static readonly MvxColor FalseBGColor = new MvxColor(0xD6, 0xF6, 0xFF);

    protected override MvxColor Convert(bool value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return value ? TrueBGColor : FalseBGColor;
    }
}

In my AXML layout, I have the following code:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:local="http://schemas.android.com/apk/res-auto"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    local:MvxBind="BackgroundColor MyBooleanValue, Converter=BackgroundColor">
  <TextView
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:gravity="center"
      android:textSize="18dp"
      local:MvxBind="Text MyText" />
</LinearLayout>

I'm getting the following error:

Failed to create target binding for binding BackgroundColor for MyBooleanValue

The full error trace is as follows:

MvxBind:Error:  8.58 Problem seen during binding execution for binding BackgroundColor for MyBooleanValue - problem InvalidCastException: Cannot cast from source type to destination type.
03-05 14:18:46.434 I/mono-stdout(16474): MvxBind:Error:  8.58 Problem seen during binding execution for binding BackgroundColor for MyBooleanValue - problem InvalidCastException: Cannot cast from source type to destination type.
03-05 14:18:46.434 I/mono-stdout(16474):      at Cirrious.MvvmCross.Plugins.Color.Droid.BindingTargets.MvxViewBackgroundColorBinding.SetValueImpl (System.Object target, System.Object value) [0x00000] in <filename unknown>:0 
      at Cirrious.MvvmCross.Plugins.Color.Droid.BindingTargets.MvxViewBackgroundColorBinding.SetValueImpl (System.Object target, System.Object value) [0x00000] in <filename unknown>:0 
  at Cirrious.MvvmCross.Binding.Bindings.Target.MvxConvertingTargetBinding.SetValue (System.Object value) [0x00000] in <filename unknown>:0 
03-05 14:18:46.434 I/mono-stdout(16474):   at Cirrious.MvvmCross.Binding.Bindings.Target.MvxConvertingTargetBinding.SetValue (System.Object value) [0x00000] in <filename unknown>:0 
  at Cirrious.MvvmCross.Binding.Bindings.MvxFullBinding.UpdateTargetFromSource (System.Object value) [0x00000] in <filename unknown>:0 

So, I'm honestly not sure where to go from here. Is what I'm attempting possible? Am I using the right MvvmCross converter? Any pointers would be much appreciated.


Update:

Changing the converter to:

public class BackgroundColorValueConverter : MvxColorValueConverter
{
    private static readonly MvxColor TrueBGColor = new MvxColor(0xDB, 0xFF, 0xCE);
    private static readonly MvxColor FalseBGColor = new MvxColor(0xD6, 0xF6, 0xFF);

    protected override MvxColor Convert(object value, object parameter, System.Globalization.CultureInfo culture)
    {
        return (bool)value ? TrueBGColor : FalseBGColor;
    }
}

... resolved my problem. I also had TextColor MyBooleanValue, Converter=TextColor on my LinearLayout, which functioned similarly to BackgroundColorValueConverter, and I was getting the same error about failing to create target bindings.

Once I changed my AXML to read:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:local="http://schemas.android.com/apk/res-auto"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    local:MvxBind="BackgroundColor MyBooleanValue, Converter=BackgroundColor">
  <TextView
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:gravity="center"
      android:textSize="18dp"
      local:MvxBind="Text MyText; TextColor MyBooleanValue, Converter=TextColor" />
</LinearLayout>

... everything worked as intended. For anyone who happens to stumble across this in the future: don't try to bind TextColor on a LinearLayout, because it doesn't work like that!

Monasticism answered 5/3, 2014 at 18:53 Comment(0)
V
3

There's a working sample of BackgroundColor binding in https://github.com/MvvmCross/MvvmCross-Tutorials/blob/master/ValueConversion/ValueConversion.UI.Droid/Resources/Layout/View_Colors.axml

This uses the BackgroundColor binding from https://github.com/MvvmCross/MvvmCross/blob/v3.1/Plugins/Cirrious/Color/Cirrious.MvvmCross.Plugins.Color.Droid/BindingTargets/MvxViewBackgroundColorBinding.cs

Does this sample work for you?

If yes, can you spot the difference between that sample and the one you are using? Is it some problem with the Color plugin? (Is that loaded in your UI project?) Is it an issue with LinearLayout versus TextView? Is there any more error trace you can provide? The one line of trace you have provided is created on https://github.com/MvvmCross/MvvmCross/blob/1ec7bc5f0307595c7ae11f56727dd0e9d2a2262f/Cirrious/Cirrious.MvvmCross.Binding/Bindings/MvxFullBinding.cs#L139 - but there's normally other trace before that line.

If no, then that's worrying as it means it's a general bug...


Update: (after more info provided)

I think the problem is in your ValueConverter - to work with Android, your ValueConverter has to end up with a Native type - not the platform-independent MvxColor. The error you are seeing is an invalid cast exception - because the binding is trying to cast your MvxColor to an Android.Graphics.Color in https://github.com/MvvmCross/MvvmCross/blob/v3.1/Plugins/Cirrious/Color/Cirrious.MvvmCross.Plugins.Color.Droid/BindingTargets/MvxViewBackgroundColorBinding.cs#L25

To convert to Native, you can use the MvxColorValueConverter base class - see https://github.com/MvvmCross/MvvmCross/blob/v3.1/Plugins/Cirrious/Color/Cirrious.MvvmCross.Plugins.Color/MvxColorValueConverter.cs

One example of this is https://github.com/MvvmCross/MvvmCross-Tutorials/blob/master/ValueConversion/ValueConversion.Core/Converters/Converters.cs#L35

public class ContrastColorConverter : MvxColorValueConverter
{
    protected override MvxColor Convert(object value, object parameter, CultureInfo culture)
    {
        var input = (MvxColor) value;
        var brightnessToUse = SimpleContrast(input.R, input.G, input.B);
        return new MvxColor(brightnessToUse, brightnessToUse, brightnessToUse);
    }

    private static int SimpleContrast(params int[] value)
    {
        // this is only a very simple contrast method
        // for more advanced methods you need to look at HSV-type approaches

        int max = 0;
        foreach (var v in value)
        {
            if (v > max)
                max = v;
        }

        return 255 - max;
    }
}

There are some docs on Color Converters in https://github.com/MvvmCross/MvvmCross/wiki/Value-Converters#wiki-the-mvx-color-valueconverters

Vanadium answered 5/3, 2014 at 20:16 Comment(3)
Ah - I see the problem... will update my answer (please also edit your question to include that error trace - it really will help the next person along)Vanadium
Thanks. Sorry to be a pain, but please put the trace in the question rather than in pastebin - putting the trace inside the question will help with search optimisation and will avoid any future issues where the trace might go missing. Sorry <- my StackOverflow OCD kicking in :)Vanadium
Thanks, Stuart! I've updated my question to include the error trace as well as something I noticed with regards to TextColor on a LinearLayout (and how it doesn't work, for dummies like me).Monasticism
M
0

You're returning a boolean on your method, where it's expecting a MvxColor object.

    protected override MvxColor Convert(object value, object parameter, System.Globalization.CultureInfo culture)
{
    (bool)value ? return TrueBGColor : return FalseBGColor;
}
Maid answered 5/3, 2014 at 19:13 Comment(1)
I've updated my question. I don't think that is the problem though - it's returning either TrueBGColor or FalseBGColor based on the value of value.Monasticism
R
0

faced the same error about "Failed to create target binding ...", simply moved the converter from folder under core-PCL project to a new folder under Droid project did the trick for me :)

Rap answered 23/10, 2016 at 11:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.