user1818298
user1818298

Reputation: 569

Activity Indicator not displaying until all code has executed

Basically I have an activity indicator that doesn't display until all of the other code in the method has executed. I've looked and the IsBusy property is getting set to true on both the code side (login page) and the xaml binding (login xaml) so I know the correct value is at least getting passed around.

I'm pretty sure I have everything set up correctly as far as async / await goes to not lock anything.

I have a BaseViewModel class that all of my view models use. Here's the code in there for IsBusy:

bool isBusy = false;
    public bool IsBusy
    {
        get { return isBusy; }
        set { SetProperty(ref isBusy, value); }
    }

    protected bool SetProperty<T>(ref T backingStore, T value,
        [CallerMemberName]string propertyName = "",
        Action onChanged = null)
    {
        if (EqualityComparer<T>.Default.Equals(backingStore, value))
            return false;

        backingStore = value;
        onChanged?.Invoke();
        OnPropertyChanged(propertyName);
        return true;
    }

Here's my XAML for login page. The activity indicator is placed inside a single Stack Layout inside the Content Page tag:

<ActivityIndicator IsRunning="{Binding IsBusy}"
                     IsVisible="{Binding IsBusy}"
                      HeightRequest="40"
                      VerticalOptions="CenterAndExpand"
                      HorizontalOptions="CenterAndExpand">
        <ActivityIndicator.WidthRequest>
            <OnPlatform x:TypeArguments="x:Double" iOS="100" Android="100" />
        </ActivityIndicator.WidthRequest>
        <ActivityIndicator.Color>
            <OnPlatform x:TypeArguments="Color"
                  iOS="#2499CE" />
        </ActivityIndicator.Color>
    </ActivityIndicator>

And here is the LoginPageViewModel code. If I'm understanding this correctly the indicator should display as soon as it's set to true on the first line and then disappear after the API call has been made and the user isn't authenticated.

public async void OnLogin()
    {
        IsBusy = true;

        var isAuthenticated = await LoginPageValidation.IsAuthenticated(email, password);
        if (!isAuthenticated )
        {
            IsBusy = false;
            IsForgotPasswordLabelVisible = true;
            DisplayUserAndPasswordMismatchPrompt();
            return;
        }
    }

I'm sure the issue is something small but I'm just not seeing it.

EDIT: Adding IsAuthenticated methods

IsAuthenticated

public static async Task<bool> IsAuthenticated(string email, string password)
    {
        var isAuthenticated = false;
        try
        {
            var payload = $"{{\n\t\"Email\":\"{email}\",\n\t\"Password\":\"{password}\"\n}}";
            var response = await LoginApi.Authenticate(payload);
            isAuthenticated = bool.Parse(response["isAuthenticated"].ToString());
        }
        catch (Exception e)
        {
            // log stuff here
        }

        return isAuthenticated;
    }

Authenticate API call:

public static async Task<JObject> Authenticate(string payloadBody)
    {
        IRestResponse response = null;
        try
        {
            var client = new RestClient($"{url}/authenticate");
            var request = new RestRequest(Method.POST);
            request.AddHeader("Content-Type", "application/json");
            request.AddParameter("undefined", payloadBody, ParameterType.RequestBody);
            response = client.Execute(request);
        } catch (Exception e)
        {
            // log some bad stuff here
        }

        return JObject.Parse(response.Content);
    }

Upvotes: 0

Views: 338

Answers (2)

Leo Zhu
Leo Zhu

Reputation: 14971

Through your updated codes of Authenticate method,you could change

 client.Execute;

to

 client.ExecuteAsync

in this case you will display your ActivityIndicator as your expect

Upvotes: 1

Adlorem
Adlorem

Reputation: 1507

Make sure your viewmodel implements INotifyPropertyChanged then:

    public bool IsBusy
    {
        set { isBusy = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsBusy))); }
        get { return isBusy; }
    }

Upvotes: 0

Related Questions