rwahid
rwahid

Reputation: 111

Xamarin forms tabbed page not retrieving data from in OnAppearing

I retrieve data from the Azure database to show one of the tabbed pages. when calling the method from ViewModel in OnAppearing not retrieve data, but when click the button it retrieves and shows on the page.

Please advice If I have constructed ViewModel and view correctly? if so why it doesn't work. ?

Connection manager:

    public partial class DatabaseManager
    {
    static DatabaseManager defaultInstance = new DatabaseManager();
    MobileServiceClient client;
    IMobileServiceTable<Person> personTable;

    private DatabaseManager()
    {
        this.client = new MobileServiceClient(Constants.AzureMobileAppURL);

        this.personTable = client.GetTable<Person>();
    }

    public static DatabaseManager DefaultManager
    {
        get
        {
            return defaultInstance;
        }
        private set
        {
            defaultInstance = value;
        }
    }

    public MobileServiceClient CurrentClient
    {
        get { return client; }
    }
  }

Model:

   public class Person
   {
     [JsonProperty(PropertyName = "FirstName")]
    public string FirstName
    {
        get { return firstName; }
        set { firstName = value; }
    }

    [JsonProperty(PropertyName = "DisplayName")]
    public string DisplayName
    {
        get { return displayName; }
        set { displayName = value; }
    }

    [JsonProperty(PropertyName = "LastName")]
    public string LastName
    {
        get { return lastName; }
        set { lastName = value; }
    }
   }

ViewModel:

     public class ProfilePageViewModel : ViewModelBase
     {
    DatabaseManager manager;
    string firstName = "";
    string lastName = "";
    string displayName = "";;
    IMobileServiceTable<Person> personTable;

     public ProfilePageViewModel()
     {
       manager = DatabaseManager.DefaultManager;
        this.personTable = manager.CurrentClient.GetTable<Person>();

        RefreshCommand = new Command(
            execute: async () =>
            {
                try
                {
                    await GetProfileAsync();
                }
                catch
                {

                }

            });
          }

      public async Task GetProfileAsync()
       {
        try
        {

            IEnumerable<Person> items = await personTable
               .Where(pserson => pserson.Active)
               .ToEnumerableAsync();

            foreach (var item in items)
            {
                FirstName = item.FirstName;
                LastName = item.LastName;
                DisplayName = item.DisplayName;

            }

        }
        catch (Exception e)
        {

        }
       }

    public string FirstName
    {
        private set { SetProperty(ref firstName, value); }
        get { return firstName; }
    }

    public string LastName
    {
        private set { SetProperty(ref lastName, value); }
        get { return lastName; }
    }

    public string DisplayName
    {
        private set { SetProperty(ref displayName, value); }
        get { return displayName; }
    }

   public ICommand RefreshCommand { private set; get; }
 }

View:

  ProfilePage.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"
         x:Class="SLSNZ.Views.ProfilePage"
         xmlns:controls="clr- 
             namespace:ImageCircle.Forms.Plugin.Abstractions;
             assembly=ImageCircle.Forms.Plugin"
             xmlns:local="clr-namespace:SLSNZ.ViewModels"
             Title="Profile">

  <ContentPage.Resources>
    <ResourceDictionary>
        <local:ProfilePageViewModel x:Key="viewModel">

        </local:ProfilePageViewModel>
    </ResourceDictionary>
  </ContentPage.Resources>

<ContentPage.Icon>
    <OnPlatform x:TypeArguments="FileImageSource">
        <On Platform="iOS" Value="icon-profile.png" />
    </OnPlatform>
</ContentPage.Icon>

<ContentPage.Padding>
    <OnPlatform x:TypeArguments="Thickness"                     
                iOS="0, 20, 0, 0" />
</ContentPage.Padding>

    <StackLayout BindingContext="{StaticResource viewModel}">
    <Label Text="Display Name"
               TextColor="Gray"
               FontSize="Small"                
               HorizontalOptions="Start" /> 

    <Label Text="{Binding DisplayName}" 
                VerticalOptions="Center"
               HorizontalOptions="Start"                
               VerticalOptions="Start/>

     <Label Text="First Name"
               TextColor="Gray"
               FontSize="Small"                
               HorizontalOptions="Start" />

     <Label Text="{Binding FirstName}"              
               FontSize="Large" 
               HorizontalOptions="Start"                
               VerticalOptions="Start" />

     <Label Text="Last Name"  
               TextColor="Gray"
               FontSize="Small"                
               HorizontalOptions="Start" />

     <Label Text="{Binding LastName}"              
               FontSize="Large"                
               HorizontalOptions="Start"                
               VerticalOptions="Start" /> 

     <Button Text="Refresh"
                        Command="{Binding RefreshCommand}"
                        Grid.Row="0" Grid.Column="1"/>

    </StackLayout>
    </ContentPage>

View:

  ProfilePage.cs

  public partial class ProfilePage : ContentPage
   {
  ProfilePageViewModel viewModel;

  public ProfilePage()
    {
        InitializeComponent();
        viewModel = new ProfilePageViewModel();

    }

   protected override async void OnAppearing()
    {

        base.OnAppearing();
        await viewModel.GetProfileAsync();
    }
  }

ViewModelBase:

 public class ViewModelBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected bool SetProperty<T>(ref T storage, T value,
                                  [CallerMemberName] string propertyName = 
    null)
    {
        if (Object.Equals(storage, value))
            return false;

        storage = value;
        OnPropertyChanged(propertyName);
        return true;
    }

    protected void OnPropertyChanged([CallerMemberName] string propertyName 
     = null)
    {
        PropertyChanged?.Invoke(this, new 
        PropertyChangedEventArgs(propertyName));
    }
}

Upvotes: 0

Views: 612

Answers (1)

TResponse
TResponse

Reputation: 4125

In your view by the time you await viewModel.GetProfileAsync(); The view will already render.

Your GetProfileAsync in the View Model does an await so will get the data then update it.

I suggest changing the IMobileServiceTable personTable to a property and implement a on Property change to notify the view that the data has changes.

So your viewmodel should implement INotifyPropertyChanged

 public event PropertyChangedEventHandler PropertyChanged;
    public void OnPropertyChanged([CallerMemberName] string name = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
    }

Then when the Data Changes you can notify it in the view model like:

OnPropertyChanged("personTable");

Also in your view change your code to:

pre-initialize the viewmodel:

public ProfilePage()
    {
        InitializeComponent();

         SetViewModel();

    }

   protected async void SetViewModel()
    {  
       viewmodel = await viewModel.GetProfileAsync();
    }

This way you wont block the UI thread and when you call the OnPropertyChnage it will notify your view to update.

UPDATE:

I have created a small sample Xamarin project for you to demonstrate how you can bind and notify the view of changes.

You had a few issues in your view as well where your DisplayName label was not closed properly and you had duplicate properties for HorizontalOptions in some labels.

Download this Xamarin sample. It had hard coded data but will show you the flow of setting the data and the Binding Context of the View without locking the UI thread.

https://github.com/loanburger/54430503

Upvotes: 1

Related Questions