2
votes

I'm adding a resource through XAML in my App.xaml. This resource is a implicit style that will be assigned to a CustomControl. The CustomControl contains a label.

To set the TextColor of this label I create a bindable property on the CustomControl and assign a value with the implicit style. Using the PropertyChanged method of the BindableProperty I set the TextColor of the Label inside my CustomControl.

<Style TargetType="CustomControl" >
     <Setter Property="InnerLabelTextColor" Value="Green" />
</Style>

-

private static void InnerLabelTextColorChanged(BindableObject bindableObject, object oldValue, object newValue)
{
    ((CustomControl)bindableObject).InnerLabel.TextColor = (Color)newValue;
}

This used to work in XF 2.3.2.127 but when I updated to XF 2.3.4.270 I started getting a NullReferenceException in the CustomControl - BindableProperty - InnerLabelTextColorChanged method.

The PropertyChanged method is called before executing the constructor. My InnerLabel is null when the PropertyChanged method is executed which causes the NullReferenceException.

I was wondering if this behaviour is the requested XF behaviour or if it is a bug?

If it is the requested behaviour, can anyone provide the correct way of handling this situation?

Thanks!

Edit - custom control code sample

public sealed class CustomControl : ContentView
{
    public static readonly BindableProperty InnerLabelTextColorProperty =
        BindableProperty.Create("InnerLabelTextColor", typeof(Color), typeof(CustomControl), Color.Black,
            BindingMode.OneWay, null, CustomControl.InnerLabelTextColorChanged, null, null, null);


    public CustomControl()
    {
        this.InnerLabel = new Label();

        this.Content = this.InnerLabel;
    }


    public Label InnerLabel { get; set; }


    public Color InnerLabelTextColor
    {
        get
        {
            return (Color)this.GetValue(CustomControl.InnerLabelTextColorProperty);
        }
        set
        {
            this.SetValue(CustomControl.InnerLabelTextColorProperty, value);
        }
    }


    private static void InnerLabelTextColorChanged(BindableObject bindableObject, object oldValue, object newValue)
    {
        ((CustomControl)bindableObject).InnerLabel.TextColor = (Color)newValue;
    }
}
1
Put your custom control codeZiyad Godil
@ZiyadGodil. I have added a code sample to the question.Jasper Callens

1 Answers

2
votes

I had worked on a similar issue sometime back, the only difference being it was encountered in a XAML based control.

I think the root cause for this problem is that (when we use an global-implicit style like that) the base constructor tries to set that bindable property, and as derived constructor is still waiting for its turn, we encounter the null reference.

Simplest way to resolve this would be to use Binding to set properties on inner-child controls (reference):

public CustomControl()
{
    this.InnerLabel = new Label();

    // add inner binding
    this.InnerLabel.SetBinding(Label.TextColorProperty, 
         new Binding(nameof(InnerLabelTextColor), 
                     mode: BindingMode.OneWay, 
                     source: this));  

    this.Content = this.InnerLabel;
}