Data Binding and INotifyPropertyChanged

JenniferTruongJenniferTruong USMember, University

I'm currently making an app using Xamarin Forms. This app will first call a REST service to retrieve the data and display them then store those data into a SQLite Database. I have an update button where if I click on it, it will prompt the REST service once again to retrieve newer data and replace the old data while the app is running. I have tried to implement the INotifyPropertyChanged but the value just wont' change for me. Am I missing anything with my code below? Thanks!

Vitals Object:

public class Vitals { public string Height { get; set; } public string ID { get; set; } public string Weight { get; set; } }

Update Method:

async void OnUpdate(object sender, EventArgs e) { string tempUser = globalPatient.Username; string tempPin = globalPatient.PIN; patUpdate = patientManager.GetPatientByUsername (tempUser, tempPin).Result; App.PatientDB.DeletePatient(tempID); App.PatientDB.AddNewPatient (patUpdate, tempPin); DisplayAlert ("Updated", "Your information has been updated!", "OK"); }

VitalsViewModal:

`public class VitalsViewModel: INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;

public VitalsViewModel (Patient patient)
{
    vitals = patient.Vitals;

}
private List<Vitals> _vitals;

public List<Vitals> vitals { 
    get {return _vitals; }

    set {
        if (_vitals != value) {
            _vitals = value;
            OnPropertyChanged ("vitals");
        }
    }
}

protected virtual void OnPropertyChanged(string propertyName)
{
    if (PropertyChanged != null)
    {
        PropertyChanged(this,
            new PropertyChangedEventArgs(propertyName));
    }
}

}`

Answers

  • DanielLDanielL PLInsider ✭✭✭✭
    edited September 2015
    1. Change List<Vitals> to ObservableCollection<Vitals>
    2. If user data can be updated, Vitals class could also implement INotifyPropertyChanged
  • AlessandroCaliaroAlessandroCaliaro ITMember ✭✭✭✭✭

    I suggest to use fody.propertychange to simplify your code

  • JenniferTruongJenniferTruong USMember, University

    @DanielL

    `public class Vitals: INotifyPropertyChanged
    {
    private string _Height;
    public string Height
    {
    get{return _Height; }
    set {if (_Height != value) {
    _Height = value;
    OnPropertyChanged ("Height");
    } }
    }

                private string _Weight;
        public string Weight 
        {
            get{return _Weight; } 
            set {if (_Weight != value) {
                    _Weight = value;
                    OnPropertyChanged ("Weight");
                } }
        }
    

    }`

    @AlessandroCaliaro

    I took a look at PropertyChange.Fody and it looked really simple. Tried installing the nudget but I keep getting the no weaver error when trying to compile.

  • DanielLDanielL PLInsider ✭✭✭✭
    edited September 2015

    @JenniferTruong You need to use ObservableCollection instead of Lists (it notifies UI about collection items changes).

    About Fody. If you're using Xamarin Studio, you have to create CodyWeaver.xml by yourself:

    look here: https://forums.xamarin.com/discussion/comment/155710/#Comment_155710
    and here: http://arteksoftware.com/fody-propertychanged-xamarin-studio/ (step by step)

  • JenniferTruongJenniferTruong USMember, University
    edited September 2015

    @DanielL By notify UI about collection items changes, do you mean like the old value will automatically change to the new value? I just switch the Lists to ObservableCollection but the value is still the same.

    Does it have to do with how I map the data?

    Vitals Data from REST -> Deserialize and put into DB -> Retrieve Vitals from DB -> Convert Vitals data from Lists to ObservableCollection -> Put the converted data into a Vitals to be display object-> Bind and display in ViewModel

  • DanielLDanielL PLInsider ✭✭✭✭

    @JenniferTruong Everytime you bind some properties, UI subscribes to object changes through PropertyChanged event of INotifyPropertyChanged interface implementation.

    Differences between List and ObservableCollection is that, it can also subscribe to its items changes when collection changes (eg. you insert some items to the collection, delete some item, etc). It doesn't work if one of the collection item property changes (you update some name, etc). For that you need binding and INotifyPropertyChanged implementation.

    Vitals Data from REST -> Deserialize and put into DB -> Retrieve Vitals from DB -> Convert Vitals data from Lists to ObservableCollection -> Put the converted data into a Vitals to be display object-> Bind and display in ViewModel

    Does you ObservableCollection property also implement OnPropertyChanged, like:

    private ObservableCollection<Vitals> list;
    public ObservableCollection<Vitals> List 
    {
        get { return list; } 
        set {if (list != value) {
                list = value;
                OnPropertyChanged ("List");
        } }
    }
    

    BTW: you can easily convert list to ObservableCollection:

    ObservableCollection<string> collection = new ObservableCollection<string>(yourListHere);

  • JenniferTruongJenniferTruong USMember, University

    @DanielL
    Follow your suggestions, i tried to use Fody.PropertyChange. Could it be that I'm still missing anything?

    This is the whole object:
    [ImplementPropertyChanged] public class Vitals { public string Height { get; set; } public string Weight { get; set; } }

    [ImplementPropertyChanged] public class Patient { public string Username { get; set; } public string FullName { get; set; } public ObservableCollection<Vitals> Vitals { get; set; } }

    ViewModel:

    [ImplementPropertyChanged] public class VitalsViewModel { public VitalsViewModel (Patient patient) { vitals = patient.Vitals; } public ObservableCollection<Vitals> vitals { get; set;} }

  • DanielLDanielL PLInsider ✭✭✭✭

    It looks good. Maybe it's a binding problem? Do you have a code? Another thing could be Fody not supporting not-standard naming (you have lowercase property names) - you could also check that.

  • JenniferTruongJenniferTruong USMember, University
    edited October 2015

    @DanielL I see! Thanks for confirming that! Also here is the binding code in Xaml. The binding is working and displaying data all correctly. It's just that the data won't change upon calling the update function. Like old Height is 170 , and upon calling the REST new Height is 180. I will try to remove Fody and try to code it the regular way.

    <ListView x:Name="Vitals" ItemTapped="OnItemTapped" ItemsSource="{Binding vitals}" RowHeight="80" BackgroundColor="Transparent"> <ListView.ItemTemplate> <DataTemplate> <ViewCell> <ViewCell.View> <StackLayout Orientation="Vertical" Spacing="0" Padding="15"> <Grid> <Image Source="bgl-60.png" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="1" Grid.RowSpan="2" /> <Label Font="17" Text="{Binding Height} " FontAttributes="Bold" TextColor="#449BC4" Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="3" /> <Label Font="14" Text="{Binding Weight, StringFormat='Weight: {0}'}" FontAttributes="Bold" Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="3" /> <Label Font="10" Text=" " TextColor="#8A2BE2" Grid.Row="3" Grid.Column="1" Grid.ColumnSpan="3" /> <Grid.ColumnDefinitions> <ColumnDefinition Width="30" /> <ColumnDefinition Width="2*" /> <ColumnDefinition Width="2*" /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> </Grid> </StackLayout> </ViewCell.View> </ViewCell> </DataTemplate> </ListView.ItemTemplate> </ListView>

  • JulienRosen.1140JulienRosen.1140 CAMember
    edited October 2015

    Could you try your code outside of a ListView? Say you just pull out the first Vital and then do an Update.

Sign In or Register to comment.