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
List<Vitals>
toObservableCollection<Vitals>
I suggest to use fody.propertychange to simplify your code
@DanielL
`public class Vitals: INotifyPropertyChanged
{
private string _Height;
public string Height
{
get{return _Height; }
set {if (_Height != value) {
_Height = value;
OnPropertyChanged ("Height");
} }
}
}`
@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.
@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)
@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
@JenniferTruong Everytime you bind some properties, UI subscribes to object changes through
PropertyChanged
event ofINotifyPropertyChanged
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 andINotifyPropertyChanged
implementation.Does you ObservableCollection property also implement OnPropertyChanged, like:
BTW: you can easily convert list to ObservableCollection:
ObservableCollection<string> collection = new ObservableCollection<string>(yourListHere);
@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;} }
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.
@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>
Could you try your code outside of a ListView? Say you just pull out the first Vital and then do an Update.