Home > database >  Nested object is not updating Binding Xamarin.Forms
Nested object is not updating Binding Xamarin.Forms

Time:02-21

I want to make cards with Name and Details.

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
             xmlns:vm="clr-namespace:MinerController.ViewModels" 
             xmlns:cards="clr-namespace:Syncfusion.XForms.Cards;assembly=Syncfusion.Cards.XForms"
             x:Class="MinerController.Views.Dashboard"
             Appearing="ContentPage_Appearing">
    <ContentPage.BindingContext>
        <vm:DashboardVM />
    </ContentPage.BindingContext>
    <ContentPage.Content>
        <StackLayout>
            <Label Text="Datos de las pools" FontSize="Title" HorizontalTextAlignment="Center"  />
            <StackLayout BindableLayout.ItemsSource="{Binding UserInfo}" BindableLayout.EmptyView="No data." Orientation="Horizontal">
                <BindableLayout.ItemTemplate>
                    <DataTemplate>
                        <cards:SfCardView BackgroundColor="SlateGray" HasShadow="True" WidthRequest="100" Margin="5" Padding="5">
                        <Grid>
                            <Label Grid.Row="0" Text="{Binding Name}"/>
                            <Label Grid.Row="1" Text="{Binding LastUpdateHumanized}" />
                            <StackLayout Grid.Row="2" BindableLayout.ItemsSource="{Binding AdditionalInfo}" BindableLayout.EmptyView="No data.">
                                <BindableLayout.ItemTemplate>
                                    <DataTemplate>
                                        <Grid>
                                            <Label Grid.Row="0" Text="{Binding Address}" />
                                            <Label Grid.Row="1" Text="{Binding Availability}" /> 
                                        </Grid>
                                    </DataTemplate>
                                </BindableLayout.ItemTemplate>
                            </StackLayout>
                        </Grid>
                        </cards:SfCardView>
                    </DataTemplate>
                </BindableLayout.ItemTemplate>
            </StackLayout>
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

ViewModel:

internal class DashboardVM : BaseViewModel
{
  private InternalService internalService;
  public ObservableCollection<UserInfo> UserInfo { get; private set; }
  public DashboardVM()
  {
    UserInfo = new ObservableCollection<UserInfo>();
    internalService = new InternalService();
    if (ConfigService.Configuration != null)
    {
      foreach(var person in ConfigService.Configuration.Persons)
      {
        UserInfo.Add(new UserInfo() { Name = person.Name, AdditionalsInfo = new ObservableCollection<AdditionalInfo>() });
        foreach(var additionalinfo in person.AdditionalsInfo)
        {
          UserInfo.Last().AdditionalsInfo.Add(new AdditionalInfo() { address = person.Address, Availiability = person.Availability });
        }
      }
      _ = TimedUpdate();
    }
  }
  private async Task TimedUpdate()
  {
    while (true)
    {
      await UpdateInfo();
      await Task.Delay(60000);
    }
  }
  public async Task UpdateInfo()
  {
    foreach (var user in UserInfo)
    {
      foreach (var additionalInfo in user.AdditionalsInfo)
      {
        additionalInfo.Availability = await internalservice.GetAvailability(user.Name, additionalInfo.Address);
      }
      user.LastUpdate = DateTime.Now;
    }
    OnPropertyChanged(nameof(UserInfo));
  }
}

Models:

internal class UserInfo
{
  public string Name { get; set; }
  public ObservableCollection<AdditionalInfo> AdditionalsInfo { get; set; }
  public DateTime LastUpdate { get; set; }
  public string LastUpdateHumanized { get { return LastUpdate.Humanize(); } }

}
internal class AdditionalInfo
{
  public string Address { get; set; }
  public string Availability { get; set; }
}

The result of this code is the following: when the first time I load, it get all data from config file, then, periodically I need to update "availability" of the user, but when I update the object, it doesn't update on screen. Maybe binding is ignored, but why?, or the issue is because of nested object? I'm doing well? Before helping me, please read the follow: I don't want a workaround because I still need populating the "dashboard" with another things, and making something outside mvvm, I believe is ugly.

Thank you!

CodePudding user response:

Your models objects need to implement INotifyPropertyChanged in order to notify changes to the UI.

CodePudding user response:

You object is not notified that it changed. To solve your problem you can create a root class that inherits from InofifyPropertyChange .

public class Root : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        internal void RaisePropertyChanged([CallerMemberName]string propertyName ="")
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

        }

    }

then inherit any model from this class to implement Property Changed Event.

internal class AdditionalInfo : Root
{
  public string Address { get; set; }
  private string availability;
  
  public string Availability
  { 
  get{ return availability;}
  set
     { availability= value;  
       RaisePropertyChanged();
     } 
  }
}
  • Related