0

I have a custom behavior for Entry. It has a bindable property MobileCountryCode.

public class MobileNumberValidation:Behavior<Entry>
    {

        public static readonly BindableProperty MobileCountryCodeProperty =
            BindableProperty.Create(nameof(MobileCountryCode)
                ,typeof(string),typeof(MobileNumberValidation)
                ,defaultValue:String.Empty);
        public string MobileCountryCode
        {
            get=> (string)GetValue(MobileCountryCodeProperty);
            set => SetValue(MobileCountryCodeProperty, value);
        }
     
        protected override void OnAttachedTo(Entry bindable)
        {
            base.OnAttachedTo(bindable);
            this.BindingContext = bindable.BindingContext;
            bindable.Unfocused += Bindable_Unfocused;
        }

        protected override void OnDetachingFrom(Entry bindable)
        {
            base.OnDetachingFrom(bindable);
            bindable.Unfocused -= Bindable_Unfocused;
        }
        
        private void Bindable_Unfocused(object sender, FocusEventArgs e)
        {
            // Validation logic
        }
    }

I have used this custom behavior in xaml with a hardcoded string value to the property 'MobileCountryCode' and it works just fine.

<Entry
    x:Name="ent_MobileNo"
    Grid.Column="1"
    behaviors:SetFocusOnEntryCompletedBehavior.NextElement="{x:Reference ent_name}"
    Keyboard="Email"
    Placeholder="{behaviors:Translate MobilePlaceHolder}"
    Text="">
    <Entry.Behaviors>
        <customBehaviour:MobileNumberValidation
            x:Name="MobileNoFormat"
            InValidStyle="{x:StaticResource InvalidEntry}"
            MobileCountryCode="+1" />
    </Entry.Behaviors>
</Entry>
<!--this is all good-->

But when I change the value form hardcoded string to a Binding it gives an error XFC0009: No property, BindableProperty, or event found for "CodeInString", or mismatching type between value and property.

<Entry
    x:Name="ent_MobileNo"
    Grid.Column="1"
    behaviors:SetFocusOnEntryCompletedBehavior.NextElement="{x:Reference ent_name}"
    Keyboard="Email"
    Placeholder="{behaviors:Translate MobilePlaceHolder}"
    Text="">
    <Entry.Behaviors>
        <customBehaviour:MobileNumberValidation
            x:Name="MobileNoFormat"
            InValidStyle="{x:StaticResource InvalidEntry}"
            MobileCountryCode="{Binding CodeInString}" />
    </Entry.Behaviors>
</Entry>
<!--this gives error-->

CodeInString is a property in the page's View model.

public string CodeInString {get; set;} = "+22"

How can this issue be resolved??

I have gone through other similar question here but none of the solution worked for me. The same value can be binded to Label Text and Entry Text and it runs without any issue and give the correct value. I have binded it to all the other string Properties of its VM and still no luck.

Edit: I have added an extra bindable property IsInValid of type bool. This also has the same issue with binding to the viewmodel property.

public class MobileNumberValidation:Behavior<Entry>
{
    private static readonly BindableProperty IsInValidProperty = 
        BindableProperty.Create(nameof(IsInValid),typeof(bool),typeof(MobileNumberValidation),defaultValue:false);
    public bool IsInValid
    {
        get=>(bool)GetValue(IsInValidProperty);
        set => SetValue(IsInValidProperty, value);
    }
    public static readonly BindableProperty MobileCountryCodeProperty =
        BindableProperty.Create(nameof(MobileCountryCode)
            ,typeof(string),typeof(MobileNumberValidation)
            ,defaultValue:String.Empty);
    public string MobileCountryCode
    {
        get=> (string)GetValue(MobileCountryCodeProperty);
        set => SetValue(MobileCountryCodeProperty, value);
    }

    protected override void OnAttachedTo(Entry bindable)
    {
        base.OnAttachedTo(bindable);
        bindable.Unfocused += Bindable_Unfocused;
    }

    protected override void OnDetachingFrom(Entry bindable)
    {
        base.OnDetachingFrom(bindable);
        bindable.Unfocused -= Bindable_Unfocused;
    }

    private void Bindable_Unfocused(object sender, FocusEventArgs e)
    {
        // Validation logic
    }
}

The Xaml part

<Entry
        x:Name="ent_MobileNo"
        Grid.Column="1"
        Keyboard="Email"
        Placeholder="{behaviors:Translate MobilePlaceHolder}"
        Text="{Binding MobileNo}">
        <Entry.Behaviors>
            <customBehaviour:MobileNumberValidation
                x:Name="MobileNoFormat"
                BindingContext="{Binding Path=BindingContext, Source={Reference thisPage}}"
                IsInValid="{Binding IsMobileNoValid}"
                MobileCountryCode="{Binding MobileCountryCodeSelected.MobileCode}" />
        </Entry.Behaviors>
    </Entry>

IsMobileNoValid is a boolean property in the pages ViewModel.

But on binding this to the IsInValid property of customBehaviour:MobileNumberValidation it gives the same error as before but for the IsInValid property. This works with hard coded boolean values (IsInValid="False" ,this works). The MobileCountryCode is working fine now, there is no error for this.

Ashish
  • 5
  • 3
  • Give the page that your entry is in a name like "x:name=coolpage", then in the set the source down in the entry behavior, `MobileCountryCode="{Binding CodeInString, Source={x:reference coolpage.bindingcontext}}"`. – Andrew Apr 04 '23 at 14:04
  • Thank you for the suggestion, but the issue was with the binding context being set in the `OnAttachedTo`. Setting it in the xaml resolved it. – Ashish Apr 05 '23 at 04:39

1 Answers1

0

XFC0009: No property, BindableProperty, or event found for "CodeInString", or mismatching type between value and property.

This error indicated that the "CodeInString" property cannot be found although I know you may think you have set in OnAttachedTo method:

protected override void OnAttachedTo(Entry bindable)
{
    this.BindingContext = bindable.BindingContext;
    ....
}

However, this line is executed before MainPage set its BindingContext to page's viewmodel. As a result, the bindingContext of MobileNumberValidation is null. So we could not find CodeInString property.

So for workaround, you have to set the BindingContext manually, maybe set the BindingContext of MobileNumberValidation to the page BindingContext:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
         ...
         x:Name="this">

<Entry.Behaviors>
    <customBehaviour:MobileNumberValidation BindingContext="{Binding Path=BindingContext,Source={x:Reference this}}"
        x:Name="MobileNoFormat"
        MobileCountryCode="{Binding CodeInString}" />
</Entry.Behaviors>

And don't forget to delete this line in your OnAttachedTo method:

protected override void OnAttachedTo(Entry bindable)
{
    this.BindingContext = bindable.BindingContext;
    ....
}

Hope it works for you.

Liqun Shen-MSFT
  • 3,490
  • 2
  • 3
  • 11
  • The binding context was the issue, the changes you suggested resolved my issue. Thank you :) – Ashish Apr 05 '23 at 04:37
  • I added another bindable property of type bool IsInValid. When I bind the VM property to this in the page where I'm using I'm again getting the same error for the IsInValid property. The MobileCountryCode has no errors... – Ashish May 03 '23 at 10:53
  • You could edit the question with new code or post a new question. This will help us better understand your question. – Liqun Shen-MSFT May 04 '23 at 01:00
  • I have edited the question with the updated code. – Ashish May 04 '23 at 08:33
  • try change ```private static readonly``` to ```public static readonly``` – Liqun Shen-MSFT May 04 '23 at 13:20
  • Yup this worked. But shouldn't the bindable property be private since only the IsInValid property that is interacting(?) with it. Or am I getting it all wrong? – Ashish May 05 '23 at 06:41
  • Well it is said in official doc : [Create a property](https://learn.microsoft.com/en-us/dotnet/maui/fundamentals/bindable-properties?view=net-maui-7.0#create-a-property) – Liqun Shen-MSFT May 05 '23 at 07:03
  • Thank you for the clarification. I guess I just need to study more. – Ashish May 06 '23 at 02:26