View appearing on the background when using Task.Run

I'm trying to make a Loading View by adding a IsLoading parameter to a custom ContentPage and when set, a View with some Labels and a ActivityIndicator appears on top. Here is the custom page:

public class PageWithLoading : ContentPage, INotifyPropertyChanged
    {
      private bool isLoading;
      public bool IsLoading
      {
        get
        {
            return this.isLoading;
        }

        set
        {
            this.isLoading = value;
            RaisePropertyChanged("IsLoading");
        }
    }

    private string _subtitle;
    public string subtitle
    {
        get
        {
            return this._subtitle;
        }

        set
        {
            this._subtitle = value;
            RaisePropertyChanged("subtitle");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public void RaisePropertyChanged(string propName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
    }


    public PageWithLoading()
    {

    }

    public void Loading(bool loading, string text = "")
    {
        IsLoading = loading;
        subtitle = text;
    }
}

If I make a Page that inherits from this, and set IsLoading = true, this should appear:

<AbsoluteLayout x:Name="loadingView" AbsoluteLayout.LayoutBounds="0,0,1,1" AbsoluteLayout.LayoutFlags="All" IsVisible="{Binding IsLoading}">
     <ContentView BackgroundColor="#222222" Opacity="0.75" AbsoluteLayout.LayoutFlags="All" AbsoluteLayout.LayoutBounds="0,0,1,1"/>

      <StackLayout BackgroundColor="White" AbsoluteLayout.LayoutBounds=".5,.35,.85,.85" AbsoluteLayout.LayoutFlags="All" VerticalOptions="Center">
       <Label Text="Carregando" FontSize="35" FontAttributes="Bold" VerticalOptions="Center" HorizontalOptions="Center" />
     <ActivityIndicator IsRunning="true" />
       <Label Text="{Binding subtitle}" FontSize="20" VerticalOptions="Center" HorizontalOptions="Center" />
     </StackLayout>

    </AbsoluteLayout>

And it works if I try to test with something simple, like:

Loading(true, "Logging in");

            await Task.Delay(3000);

            Loading(false);

but if I try to actually load something (in this case using two task to get some objects from a DynamoDB table) the view doesn't appear, but it seems to be under the rest of the page since you can see a glimpse of it when the page changes

Tagged:

Answers

  • ionixjuniorionixjunior USMember ✭✭✭

    Hi @luke094.

    A suggestion for you: don't create a shadow layer to simulate a content loading. Prefer use https://github.com/aritchie/userdialogs. This package have a "Loading" component and is more easily to manage this, your view will stay clean.

    About Task.Run, if you use this for loading remote content or perform another thing, maybe necessary update data on screen on main thread, not in background thread. Try this:

    Task.Run(async () => {
        // running in background thread
        var data = await YourRemoteCall();
    
        // remote data retrieved and updated in main thread
        Xamarin.Forms.Device.BeginInvokeOnMainThread(() => {
            YourAttribute = data;
        });
    });
    

    Remember: all changes to execute in the screen will be performed on main thread.

  • luke094luke094 BRMember

    @ionixjunior I've seen this component, but how do I add it to my page? Imagine for example that I have a page with just a button that after clicking show the loading, then after getting everything Pops another page. How do I implement that?

    Thanks!

  • ionixjuniorionixjunior USMember ✭✭✭

    @luke094 you want click in a button, load data remotely and after loading navigate to another page to show the data loaded, ok?

    So.. for use AcrDialogs in this context, you only need this:

    private async Task ButtonClick()
    {
        // call Acr to show loading content
        Acr.UserDialogs.UserDialogs.Instance.ShowLoading("Loading");
    
        // load remotely content
        var data = await YourAPI();
    
        // call Acr to hide loading content
        Acr.UserDialogs.UserDialogs.Instance.HideLoading();
    
        // navigate to another page here
    }
    

    You don't need add loading component as markup language in your page, this will be prepared in your view model, is more easily.

    I hope this helps.

Sign In or Register to comment.