question

Rainer-M avatar image
0 Votes"
Rainer-M asked LeonLu-MSFT commented

RefreshView's ActivityIndicator does not animate on first refresh

I have a RefreshView in a page. I want the data to refresh the first time it is shown, so I have this:

protected override void OnAppearing()
{
    if(!_hasRefreshedFirstTime) {
        _hasRefreshedFirstTime = true;
        TypedContext.IsRefreshing = true;
    }
}


And in my view model the refresh command is the following, with Refresh = new AsyncCommand(DoRefresh, onException: exceptionHandler);:

public IAsyncCommand Refresh { get; }

private async Task DoRefresh()
{
    IsRefreshing = true;
    _ = await DataManager.RefreshOrderHistoryAsync();
    IsRefreshing = false;
}


This works, but this first time it is refreshing the ActivityIndicator is frozen. Interestingly, after that, if I pull to refresh, the indicator animates correctly.

My question is, why in the indicator not animated correctly and how can I fix that?

dotnet-xamarin
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

1 Answer

LeonLu-MSFT avatar image
0 Votes"
LeonLu-MSFT answered LeonLu-MSFT commented

Hello,​

Welcome to our Microsoft Q&A platform!

Is TypedContext.IsRefreshing = true; a static value? If so, please do not use this way to change the loading operation.

I use the official demo. Here is running screenshot. It is running normally.

109717-image.png 109718-image.png

You can Add a new method like DoRefresh method. Keep the IsRefreshing property, but achieve the IsRefreshing property with INotifyPropertyChanged interface, here is code about MainPageViewModel.cs.

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using Xamarin.Forms;

namespace App110
{
    public class Item
    {
        public string Name { get; set; }
        public Color Color { get; set; }
    }
    public class MainPageViewModel : INotifyPropertyChanged
    {
        const int RefreshDuration = 2;
        int itemNumber = 1;
        readonly Random random;
         bool isRefreshing;

        public  bool IsRefreshing
        {
            get { return isRefreshing; }
            set
            {
                isRefreshing = value;
                OnPropertyChanged();
            }
        }

        public ObservableCollection<Item> Items { get; private set; }

        public ICommand RefreshCommand => new Command(async () => await DoRefresh());

        public MainPageViewModel()
        {
            random = new Random();
            Items = new ObservableCollection<Item>();
         
        }

        void AddItems()
        {
          
            for (int i = 0; i < 3; i++)
            {
                Items.Add(new Item
                {
                    Color = Color.FromRgb(random.Next(0, 255), random.Next(0, 255), random.Next(0, 255)),
                    Name = $"Item {itemNumber++}"
                });
            }

          
        }
  
        public async  void RefreshItemsAtFirstTimeAsync()
        {
            IsRefreshing = true;
           

        }


        public async Task DoRefresh()
        {
         
            IsRefreshing = true;

            //add your loading code
            await Task.Delay(TimeSpan.FromSeconds(RefreshDuration));
            AddItems();
            IsRefreshing = false;
        }

        #region INotifyPropertyChanged

        public event PropertyChangedEventHandler PropertyChanged;

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

        #endregion
    }
}


Then add class of bindingContext in the background code. You can execute the DoRefresh() method directly in OnAppearing method.

public partial class MainPage : ContentPage
    {
        private  bool _hasRefreshedFirstTime;

     
        MainPageViewModel mainPageViewModel;
        public MainPage()
        {
            _hasRefreshedFirstTime = false;
            mainPageViewModel =new MainPageViewModel();

            BindingContext = mainPageViewModel;
            InitializeComponent();
        }
        protected  override void OnAppearing()
        {
            base.OnAppearing();

            if (!_hasRefreshedFirstTime)
            {
                Console.WriteLine("===============================OnAppearing=====================");
                mainPageViewModel.RefreshItemsAtFirstTimeAsync();

                _hasRefreshedFirstTime = true;
            }
        }
    }




Best Regards,

Leon Lu



If the response is helpful, please click "Accept Answer" and upvote it.

Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.



image.png (23.4 KiB)
image.png (21.0 KiB)
· 9
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Thanks for the reply.

I don't understand what you mean by is 'TypedContext.IsRefreshing = true;' a static value. Can you explain more?

Also, in your example, you call 'mainPageViewModel.RefreshItemsAtFirstTimeAsync();', but 'RefreshItemsAtFirstTimeAsync' just does 'IsRefreshing = true', so what is the advantage of having the 'RefreshItemsAtFirstTimeAsync' method instead of just calling 'IsRefreshing = true' directly?

0 Votes 0 ·

Could you share code about TypedContext.cs? You can create a property IsRefreshing in ViewModel. then achieve the INotifyPropertyChanged interface.

0 Votes 0 ·

I just realized this only happens in iOS. When I try in the Android simulator it works correctly.

TypedContext is a convenience property for BindingContext that is typed. It looks like this:

protected T TypedContext => (T)BindingContext;


In this case T is OrderHistoryViewModel.

In my XAML in the RefreshView I have 'IsRefreshing="{Binding IsRefreshing}"`

In OrderHistoryViewModel I have:

public  bool IsRefreshing
{
    get { return isRefreshing; }
    set
    {
        isRefreshing = value;
        OnPropertyChanged();
    }
}


When I set IsRefreshing = true; it does work, the refresh occurs. But the problem is that the activity indicator doesn't spin, it's frozen until the refresh finishes. This only happens the first time in OnAppearing, after that, if I pull to refresh, it works correctly.

0 Votes 0 ·
Show more comments