[FIXED] How to bind data to the bindableproperty in xamarin forms

Issue

I have two pages that use the same form so I created a content view of form and apply bindable properties like this:

<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="ListContact.Extension.EditForm">
    <StackLayout Padding="20">
        <Label Text="Edit Contact Forms"
                   HorizontalOptions="Center"
                   FontSize="20"
                   TextColor="Blue"
                   VerticalOptions="Start"/>
        <Label Text="Name"/>
        <Entry x:Name="txtName" Text="{Binding NameText}" Placeholder="Name"/>
        <Label Text="Phone number"/>
        <Entry x:Name="txtPhoneNumber" Text="{Binding PhoneNumberText}" Placeholder="Phone number" Keyboard="Telephone"/>
        <Label Text="Email"/>
        <Entry x:Name="txtEmail" Text="{Binding EmailText}" Placeholder="Email" Keyboard="Email"/>
        <Label Text="Description"/>
        <Editor x:Name="txtDescription" Text="{Binding DescriptionText}" Placeholder="Description"
                    HeightRequest="70"/>
    </StackLayout>
</ContentView>

This is the code behind:

    using ListContact.ViewModel;
    using Xamarin.Forms;
    using Xamarin.Forms.Xaml;
    
    namespace ListContact.Extension
    {
        [XamlCompilation(XamlCompilationOptions.Compile)]
        public partial class EditForm : ContentView
        {
            private static readonly BindableProperty NameProperty = BindableProperty.Create("NameText", typeof(object), typeof(EditForm));
    
            public string NameText { get => (string)GetValue(NameProperty); set => SetValue(NameProperty, value); }
    
            private static readonly BindableProperty PhoneProperty = BindableProperty.Create("PhoneNumberText", typeof(string), typeof(EditForm));
    
            public string PhoneNumberText { get => (string)GetValue(PhoneProperty); set => SetValue(PhoneProperty, value); }
    
            private static readonly BindableProperty EmailProperty = BindableProperty.Create("EmailText", typeof(string), typeof(EditForm));
    
            public string EmailText { get => (string)GetValue(EmailProperty); set => SetValue(EmailProperty, value); }
    
            private static readonly BindableProperty DescriptionProperty = BindableProperty.Create("DescriptionText", typeof(string), typeof(EditForm));
    
            public string DescriptionText { get => (string)GetValue(DescriptionProperty); set => SetValue(DescriptionProperty, value); }
    
            public EditForm()
            {
                InitializeComponent();
                BindingContext = this;
            }
        }
    }

And in the view I call back this form that I created before and bind data to the bindable property like below:

This is the xaml file:

<ContentPage xmlns:local="clr-namespace:ListContact.Extension"
             xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="ListContact.View.ListContactAddingForm">
    
    <local:EditForm NameText="{Binding Name, Mode=TwoWay}" PhoneNumberText="egwebwev" EmailText="ưewevefqwf" DescriptionText="ewebe"/>
    
    <ContentPage.Content>
        <Button Text="Save"
                HorizontalOptions="Center"
                TextColor="White"
                Command="{Binding AddContactCommand}"
                BackgroundColor="#0A7CFF"/>
    </ContentPage.Content>
</ContentPage>

And this is the code behind:

namespace ListContact.View
    {
        [XamlCompilation(XamlCompilationOptions.Compile)]
        public partial class ListContactAddingForm : ContentPage
        {
            private SQLiteAsyncConnection connection;
    
            public ListContactAddingForm()
            {
                connection = new SQLiteAsyncConnection(BaseConnection.DatabasePath);
                ViewModel = new ContactViewModel(new PageService());
                InitializeComponent();
            }
    
            private ContactViewModel ViewModel
            {
                get => BindingContext as ContactViewModel;
    
                set => BindingContext = value;
            }
        }
    }
`

This is my view model:

namespace ListContact.ViewModel
{
    public class ContactViewModel : BaseViewModel
    {
        public int Id { get; set; }

        private string name;

        public string Name
        {
            get => name;
            set
            {
                SetValue(ref name, value);
            }
        }

        private string description;

        public string Description
        {
            get => description;
            set
            {
                SetValue(ref description, value);
            }
        }

        private string phoneNumber;

        public string PhoneNumber
        {
            get => phoneNumber;
            set
            {
                SetValue(ref phoneNumber, value);
            }
        }

        private string email;
        public string Email
        {
            get => email;
            set
            {
                SetValue(ref email, value);
            }
        }

        public ICommand AddContactCommand { get; private set; }
        private IPageService pageService;
        public object Alert { get; private set; }

        public ContactViewModel(IPageService pageService)
        {
            this.pageService = pageService;
            AddContactCommand = new Command(async () => await AddContacts());
        }

        private async Task AddContacts()
        {
            var newContact = new Contact()
            {
                Name = Name,
                PhoneNumber = PhoneNumber,
                Email = Email,
                Description = Description
            };

            var result = await connection.InsertAsync(newContact);

            if (result == 1)
                await App.Current.MainPage.DisplayAlert("Successfully", "", "OK");

            await pageService.PopAsycn();
        }
    }
}

But when I run this code I got the error:

No property, bindable property, or event found for "NameText", or mismatching type between value and property

My code was okay before I separated the form into another content view and call it back from the view and got this problem

So my questions are that:
Is the way that I create form and bindable property correct?
Could I bind data to the bindable property in the form? How to do it if it could?.
And how to fix the above error?

I use MVVM to build this code

Btw, sorry for my bad English

Solution

From Xamarin.Forms Bindable Properties, a bindable property can be created by declaring a public static readonly property of type BindableProperty.

 public static readonly BindableProperty NameTextProperty = BindableProperty.Create
             ("NameText", typeof(string), typeof(EditForm),"",BindingMode.OneWay,propertyChanged:NamePropertychanged);

Then you need take care of BindableProperty Name, for example, PropertyNameProperty

 public static readonly BindableProperty NameTextProperty = BindableProperty.Create
             ("NameText", typeof(string), typeof(EditForm),"",BindingMode.OneWay,propertyChanged:NamePropertychanged);
  
    public string NameText 
    { 
        get => (string)GetValue(NameTextProperty);
        set => SetValue(NameTextProperty, value);
    }

Finally, you don’t need to use Binding in EditForm, just using propertyChanged event to notify property value has changed.

private static void NamePropertychanged(BindableObject bindable, object oldValue, object newValue)
    {
        var control = (EditForm)bindable;
        control.txtName.Text = (string)newValue;
        
    }

Do one sample that you can take a look:

EditForm xaml.

<ContentView.Content>
    <StackLayout Padding="20">
        <Label
            FontSize="20"
            HorizontalOptions="Center"
            Text="Edit Contact Forms"
            TextColor="Blue"
            VerticalOptions="Start" />
        <Label Text="Name" />
        <Entry x:Name="txtName" Placeholder="Name" />
        <Label Text="Phone number" />
        <Entry
            x:Name="txtPhoneNumber"
            Keyboard="Telephone"
            Placeholder="Phone number" />
        <Label Text="Email" />
        <Entry
            x:Name="txtEmail"
            Keyboard="Email"
            Placeholder="Email" />
        <Label Text="Description" />
        <Editor
            x:Name="txtDescription"
            HeightRequest="70"
            Placeholder="Description" />
    </StackLayout>
</ContentView.Content>

 public partial class EditForm : ContentView
{
    public static readonly BindableProperty NameTextProperty = BindableProperty.Create
             ("NameText", typeof(string), typeof(EditForm),"",BindingMode.OneWay,propertyChanged:NamePropertychanged);
  
    public string NameText 
    { 
        get => (string)GetValue(NameTextProperty);
        set => SetValue(NameTextProperty, value);
    }

    public static readonly BindableProperty PhoneNumberTextProperty = BindableProperty.Create
        ("PhoneNumberText", typeof(string), typeof(EditForm),"",BindingMode.OneWay,propertyChanged:PhoneNumberchanged);

    public string PhoneNumberText 
    { 
        get => (string)GetValue(PhoneNumberTextProperty); 
        set => SetValue(PhoneNumberTextProperty, value); 
    }

    public static readonly BindableProperty EmailTextProperty = BindableProperty.Create
        ("EmailText", typeof(string), typeof(EditForm),"",BindingMode.OneWay,propertyChanged:Emailpropertychanged);     

    public string EmailText 
    { 
        get => (string)GetValue(EmailTextProperty); 
        set => SetValue(EmailTextProperty, value); 
    }

    public static readonly BindableProperty DescriptionTextProperty = BindableProperty.Create
        ("DescriptionText", typeof(string), typeof(EditForm), "", BindingMode.OneWay, propertyChanged: Descriptionchanged);


    public string DescriptionText 
    { 
        get => (string)GetValue(DescriptionTextProperty); 
        set => SetValue(DescriptionTextProperty, value); 
    }
    private static void NamePropertychanged(BindableObject bindable, object oldValue, object newValue)
    {
        var control = (EditForm)bindable;
        control.txtName.Text = (string)newValue;
        
    }
    private static void PhoneNumberchanged(BindableObject bindable, object oldValue, object newValue)
    {
        var control = (EditForm)bindable;
        control.txtPhoneNumber.Text = (string)newValue;
    }
    private static void Emailpropertychanged(BindableObject bindable, object oldValue, object newValue)
    {
        var control = (EditForm)bindable;
        control.txtEmail.Text = (string)newValue;
    }
    private static void Descriptionchanged(BindableObject bindable, object oldValue, object newValue)
    {
        var control = (EditForm)bindable;
        control.txtDescription.Text = (string)newValue;
    }

    public EditForm()
    {
        InitializeComponent();
    }
}

<StackLayout>
        <local:EditForm
            DescriptionText="{Binding option}"
            EmailText="{Binding Email}"
            NameText="{Binding Name}"
            PhoneNumberText="{Binding Phone}" />
    </StackLayout>

 public partial class Page5 : ContentPage
{
   public Contact contact1 { get; set; }
    public Page5()
    {
        InitializeComponent();
        contact1 = new Contact() { Name = "cherry", Phone = "1234567", Email = "xxxxxxxx", option = "this is test" };
        this.BindingContext = contact1 ;

    }    
}

public class Contact:ViewModelBase
{
    private string _name;
    public string Name
    {
        get { return _name; }
        set
        {
            _name = value;
            RaisePropertyChanged("Name");
        }
    }
    private string _phone;
    public string Phone
    {
        get { return _phone; }
        set
        {
            _phone = value;
            RaisePropertyChanged("Phone");
        }
    }
    private string _email;
    public string Email
    {
        get { return _email; }
        set
        {
            _email = value;
            RaisePropertyChanged("Email");
        }
    }
    private string _option;
    public string option
    {
        get { return _option; }
        set
        {
            _option = value;
            RaisePropertyChanged("option");
        }
    }
}

The ViewModelBase implementing INotifyPropertyChanged

public class ViewModelBase : INotifyPropertyChanged
{
   
    public event PropertyChangedEventHandler PropertyChanged;

    public void RaisePropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

The screenshot:

enter image description here

Answered By – Cherry Bu – MSFT

Answer Checked By – Mildred Charles (Easybugfix Admin)

Leave a Reply

(*) Required, Your email will not be published