Binding property changed not firing Xamarin.Forms + Prism

tonholistonholis USMember ✭✭
edited January 11 in Xamarin.Forms

Hello everyone!

I'm trying to consume a REST API and update the Text property of some Entry views. But as soon as I get a JSON response and set some properties of my POCO class the view it's not updating.

Take a look in my code:

ViewModel:

namespace MyApp.ViewModels
{
    public class CompanyInfoPageViewModel : ViewModelBase //which inherits BindableBase
    {
        private APIClient _apiClient;

        public CompanyInfoPageViewModel(
            INavigationService navigationService, 
            IPageDialogService pageDialogService,
            APIClient apiClient) : base(navigationService, pageDialogService)
        {
            _apiClient = apiClient;

            Company = new Company();
        }

        private Company company;
        public Company Company
        {
            get { return company; }
            set { SetProperty(ref company, value); }
        }

    //Fired on TextChanged of txtCEP Entry
        public async void FindCEP(string text)
        {
            var response = await _apiClient.GetAsync("cep/" + text);
            if (response.IsSuccessStatusCode)
            {
                var json = await response.ToJObjectAsync();
                var error = json.Value<string>("errors");
                if (error == null)
                {
                    var data = json["data"];
                    Company.Endereco = json["data"]["log_no_abrev"].ToString();
                    Company.Bairro = json["data"]["bairro"].ToString();
                    Company.Cidade = json["data"]["cidade"].ToString();

                    //And the view it's not updated ;(
                }
                else
                {
                    await PageDialogService.DisplayAlertAsync("Ops", error, "OK");
                }
            }
            else
            {
                //displays another message
            }
        }
    }

    public class Company
    {
        public string Endereco { get; set; }
        public string Bairro { get; set; }
        public string Cidade { get; set; }
        public string CEP { get; set; }     
    }
}

XAML

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
             prism:ViewModelLocator.AutowireViewModel="True"
             x:Class="MyApp.Views.CompanyInfo"
             Title="Dados da empresa">
    <StackLayout HorizontalOptions="FillAndExpand" VerticalOptions="Center">
        <StackLayout HorizontalOptions="FillAndExpand" VerticalOptions="Center" Padding="0,20,0,0">
            <Label Text="Endereço" FontSize="Large"/>
            <Entry Text="{Binding Company.CEP}" Placeholder="CEP" x:Name="txtCEP" />

            <Entry Text="{Binding Company.Endereco, Mode=TwoWay }" Placeholder="Rua, Av..." HorizontalOptions="FillAndExpand"/>
            <Entry Text="{Binding Company.Bairro}" Placeholder="Bairro" />
            <Entry Text="{Binding Company.Cidade}" Placeholder="Cidade" HorizontalOptions="FillAndExpand"/>
        </StackLayout>

        <Button Command="{Binding SalvarCommand}" Text="Salvar" Style="{StaticResource buttonPrimary}"/>
    </StackLayout>
</ContentPage>

Am I doing something wrong?

Posts

  • JimBennettJimBennett GBInsider, University, Developer Group Leader ✭✭✭✭

    The problem is you've bound the fields on your Company object, but you are not raising a property change notification for changes to those properties.

    I can think of three solutions:

    • Change Company to be a view model with property change notifications when the properties change
    • Raise a property change for Company in the CompanyInfoPageViewModel after setting the properties
    • Use passthrough properties in your CompanyInfoPageViewModel - so properties for each property on the Company object that get/set from the Company instance and raise property changes when set.
  • NMackayNMackay GBInsider, University ✭✭✭✭✭
    edited January 11

    Well there's no property for 'Empresa' so it's not going to bind, surely it should be {Binding Company.Bairro} etc

    Also, I think the Company class will have to inherit bindable base, while the company property will implement INotifyPropertyChanged the Company POCO class doesn't for individual property changes. The Company property is actually set in the vm constructor and will bind the empty class.

    Normally the service layer would just return an object you just deserialize and then set the Company property to the returned object from your Restful API, you binding as it stands would work then. Setting properties one by one seems a bit of a pain.

  • NMackayNMackay GBInsider, University ✭✭✭✭✭

    @JimBennett

    Sorry, didn't see your reply when I posted.

  • tonholistonholis USMember ✭✭

    @NMackay said:
    Well there's no property for 'Empresa' so it's not going to bind, surely it should be {Binding Company.Bairro}

    Oh I'm sorry @NMackay. Fixed!
    It's because I simplified and translated the code to post here.

    @NMackay said:
    Also, I think the Company class will have to inherit bindable base, while the company property will implement INotifyPropertyChanged the Company POCO class doesn't for individual property changes. The Company property is actually set in the vm constructor and will bind the empty class.

    l tried this but it doesn't worked.

    private Company _company;
    public Company Company
    {
        get { return _company; }
        set { SetProperty(ref _company, value); } //it implements INotifyPropertyChanged  right?
    }
    
    public class Company : BindableBase
    ...
    

    @NMackay said:
    Normally the service layer would just return an object you just deserialize and then set the Company property to the returned object from your Restful API, you binding as it stands would work then. Setting properties one by one seems a bit of a pain.

    I agree with you. But in this case, Company has a lot of properties in the real code. This API call is for feed just a few properties (related to Company's Address).

  • tonholistonholis USMember ✭✭

    @NMackay, I was just writing that it worked, exactly as your example.

    It is the first suggestion from @JimBennett .

    Thank you guys!

  • NMackayNMackay GBInsider, University ✭✭✭✭✭

    @tonholis

    Good stuff, glad you got it working.

  • RahulDawnRahulDawn USMember ✭✭

    Can anyone share with me a working solution for two-way binding using Prism Xamarin Forms

  • kalkotekedarkalkotekedar USMember ✭✭

    @NMackay said:
    @tonholis

        public class Company: BindableBase
        {
            private string _endereco;
          public string Endereco 
            {
                get { return _endereco ; }
                set { SetProperty(ref _endereco , value); }
            }
            public string Bairro { get; set; }
            public string Cidade { get; set; }
            public string CEP { get; set; }     
        }
    

    Bit late here and don't have my Prism app to reference. Try that and see if Endereco binds.

    It works for me too. Thanks @NMackay

  • RodeKubaiziRodeKubaizi USMember ✭✭

    @NMackay

        public class Company: BindableBase
        {
            private string _endereco;
          public string Endereco 
            {
                get { return _endereco ; }
                set { SetProperty(ref _endereco , value); }
            }
            public string Bairro { get; set; }
            public string Cidade { get; set; }
            public string CEP { get; set; }     
        }
    

    it Worked !!!

    Thanks

Sign In or Register to comment.