Search code examples
c#xamarinbindinglabelbehavior

Set binding value as a parameter on a behavior in Xamarin Forms


How do I set a binding value as a parameter on a behavior in Xamarin Forms?

When I do this I get: Error. No property, bindable property, or event found for 'InputValue', or mismatching type between value and property.

XAML:

<Label Grid.Column="0" x:Name="player" FontSize="Small" VerticalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand"
                                       Text="{Binding FormattedName}" >
                                    <Label.Behaviors>
                                        <local:ColorTextLabelBehavior MaxInputValue="100" MinInputValue="0" InputValue="{Binding Happiness}" />
                                    </Label.Behaviors>
                                </Label>

C#:

public class ColorTextLabelBehavior : Behavior<Label>
{
    public static readonly BindableProperty MaxValue = BindableProperty.Create("MaxValue", typeof(int), typeof(ColorTextLabelBehavior), defaultValue: 100);
    public static readonly BindableProperty MinValue = BindableProperty.Create("MinValue", typeof(int), typeof(ColorTextLabelBehavior), defaultValue: 0);
    public static readonly BindableProperty ActualValue = BindableProperty.Create("ActualValue", typeof(int), typeof(ColorTextLabelBehavior), defaultValue: 100);

    public int MaxInputValue
    {
        get { return (int)GetValue(MaxValue); }
        set { SetValue(MaxValue, value); }
    }
    public int MinInputValue
    {
        get { return (int)GetValue(MinValue); }
        set { SetValue(MinValue, value); }
    }
    public int InputValue
    {
        get { return (int)GetValue(ActualValue); }
        set { SetValue(ActualValue, value); }
    }

    void HandleTextChanged(object sender, PropertyChangedEventArgs e)
    {
        try
        {
            float percent = ((float)InputValue - (float)MinInputValue) / ((float)MaxInputValue - (float)MinInputValue);
            double resultRed = Color.Red.R + percent * (Color.Green.R - Color.Red.R);
            double resultGreen = Color.Red.G + percent * (Color.Green.G - Color.Red.G);
            double resultBlue = Color.Red.B + percent * (Color.Green.B - Color.Red.B);
            ((Label)sender).TextColor = new Color(resultRed, resultGreen, resultBlue);
        }
        catch (Exception)
        {

        }
    }

    protected override void OnAttachedTo(BindableObject bindable)
    {
        bindable.PropertyChanged += HandleTextChanged;
    }

    protected override void OnDetachingFrom(BindableObject bindable)
    {
        bindable.PropertyChanged += HandleTextChanged;
    }
}

If I hard code a value for 'InputValue' this works, but I want to be able to send a binding so that it will auto color the text.

Note this is in a listview if that matters.

Please help, I've been stuck on this and can't find any answers. I'm open to other alternatives to implementing this as well.

Thanks!!


Solution

  • I believe that the exact naming is important and that the BindableProperty has to have the name of the actual property with "Property" appended to the end. From the docs:

    The naming convention for bindable properties is that the bindable property identifier must match the property name specified in the Create method, with "Property" appended to it.

    So I believe you want something like this:

    public static readonly BindableProperty MaxInputValueProperty = BindableProperty.Create(nameof(MaxInputValue), typeof(int), typeof(ColorTextLabelBehavior), defaultValue: 100);
    public static readonly BindableProperty MinInputValueProperty = BindableProperty.Create(nameof(MinInputValue), typeof(int), typeof(ColorTextLabelBehavior), defaultValue: 0);
    public static readonly BindableProperty InputValueProperty = BindableProperty.Create(nameof(InputValue), typeof(int), typeof(ColorTextLabelBehavior), defaultValue: 100);
    
    public int MaxInputValue
    {
        get { return (int)GetValue(MaxValue); }
        set { SetValue(MaxValue, value); }
    }
    public int MinInputValue
    {
        get { return (int)GetValue(MinValue); }
        set { SetValue(MinValue, value); }
    }
    public int InputValue
    {
        get { return (int)GetValue(ActualValue); }
        set { SetValue(ActualValue, value); }
    }