John
John

Reputation: 3945

INotifyPropertyChanged - Observable collection not posting back if UI field is changed

I have been looking at many examples of INotifyPropertyChanged().

I went with the following example found on:

https://xamarindev.co.uk/mvvm-and-xamarin-forms/

Ive created a test project with this and it all works fine....using breakpoints I can see for example

public int Age
{
    get { return _person.Age; }
    set
    {
        _person.Age = value;
        OnPropertyChanged("Age");
        OnPropertyChanged("UserInfo");
    }
}

is hit when the user changes the age on the app.

Only trouble with this one is that instead of one instance of the Person, I want multiple persons, so I have added in an ObservableCollection to look like:

    public class ViewModel1 : BaseModel
{
    private ObservableCollection<Person> _Persons;
    public ObservableCollection<Person> Persons
    {
        get { return _Persons; }
        set
        {
            if (_Persons == value) return;
            _Persons = value;
        }
    }

    private Person _person;
    public ViewModel1()
    {
        Persons = new ObservableCollection<Person>();

        //// set some default here for example
        _person = new Person
        {
            Age = 21,
            FirstName = "Steve",
            LastName = "Hawkins"
        };
        Persons.Add(_person);

        _person = new Person
        {
            Age = 19,
            FirstName = "JimBob",
            LastName = "Jones"
        };
        Persons.Add(_person);
    }

    public int Age
    {
        get { return _person.Age; }
        set
        {
            _person.Age = value;
            OnPropertyChanged("Age");
            OnPropertyChanged("UserInfo");
        }
    }

    public string FirstName
    {
        get { return _person.FirstName; }
        set
        {
            _person.FirstName = value;
            OnPropertyChanged("FirstName");
            OnPropertyChanged("UserInfo");
        }
    }

    public string LastName
    {
        get { return _person.LastName; }
        set
        {
            _person.LastName = value;
            OnPropertyChanged("LastName");
            OnPropertyChanged("UserInfo");
        }
    }

    public string UserInfo
    {
        get
        {
            // return _person.PersonInfo();
            return _Persons[0].PersonInfo();
        }
    }
}

and then changed the View to display a ListView:

 <ContentPage.Content>
        <StackLayout>
                      <ListView  x:Name="producttablelist" IsVisible="True" VerticalOptions="FillAndExpand" HasUnevenRows="True" ItemsSource="{Binding Persons}" HeightRequest="1500">
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <ViewCell>
                            <StackLayout HeightRequest="120" BackgroundColor="Green" HorizontalOptions="StartAndExpand">
                                <Grid>
                                    <Grid.RowDefinitions>
                                        <RowDefinition Height="Auto"/>
                                        <RowDefinition Height="Auto"/>
                                    </Grid.RowDefinitions>
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="Auto"/>
                                        <ColumnDefinition Width="*"/>
                                    </Grid.ColumnDefinitions>
                                    <Editor Grid.Row="1" Grid.Column="1" Text="{Binding FirstName, Mode=TwoWay}" HorizontalOptions="CenterAndExpand" TextColor="Black" />
                                    <Editor Grid.Row="1" Grid.Column="2" Text="{Binding LastName, Mode=TwoWay}" HorizontalOptions="CenterAndExpand" TextColor="Black" />
                                    <Editor Grid.Row="2" Grid.Column="1" Text="{Binding Age, Mode=TwoWay}" HorizontalOptions="CenterAndExpand" TextColor="Black" />
                                    <Label Grid.Row="2" Grid.Column="2" Text="{Binding UserInfo}" HorizontalOptions="StartAndExpand" TextColor="Black" />
                                </Grid>
                            </StackLayout>
                        </ViewCell>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>

        </StackLayout>
    </ContentPage.Content>
</ContentPage>

So now, the page loads showing the 2 users, but if the user changes the age on the app...nothing happens..it doesnt post back to Age in the VM...

Could someone please help?

Been looking at other examples found on https://riptutorial.com/xaml/example/28804/binding-to-a-collection-of-objects-with-inotifypropertychanged-and-inotifycollectionchanged

and https://stackoverflow.com/questions/32667408/how-to-implement-inotifypropertychanged-in-xamarin-forms

still cant seem to get it going if I use an ObservableCollection, and as I have other logic to add in when age is changed I would like this done from the VM not from the Person class (which some examples I have found have shown)

TY for any help

Upvotes: 0

Views: 162

Answers (2)

Kudzai Dube
Kudzai Dube

Reputation: 101

Maybe try using SetProperty, it inherits from INotifyPropertyChanged i.e write your public property like the code below:

    private ObservableCollection<Person> _persons;

    public ObservableCollection<Person> Persons
    {
        get => _persons;
        set => SetProperty(ref _persons, value);
    }

ps.... your baseModel might need to inherit from INotifyPropertyChanged too if you encounter issues. I also assumed you are using an MVVM framework like PrismMVVM

Upvotes: 1

nevermore
nevermore

Reputation: 15806

As the Jason said: the "Age" entry is bound to the Age property of each person object in your data, not to the Age property of the base VM .

You do not need to write those properties in the ViewModel as they alreay exist in the Person Model.

What you really want to bind is Text="{Binding Person.FirstName, Mode=TwoWay}" not ViewModel1.FirstName.

You can write Text="{Binding FirstName, Mode=TwoWay}" here as data-binding will search the root properties until it find the property FirstName in Model Person.

Refer: data-bindings-to-mvvm

Upvotes: 0

Related Questions