0

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);
    }
user1818298
  • 509
  • 2
  • 8
  • 23
  • is the `isBusy` field protected or private? – Lindsay Dec 29 '19 at 21:58
  • Not specified so that makes it internal I think – user1818298 Dec 29 '19 at 23:44
  • I think that makes it private, though, I'm not convinced that will actually be the cause - https://stackoverflow.com/questions/2521459/what-are-the-default-access-modifiers-in-c. – Lindsay Dec 30 '19 at 02:50
  • i just made it public to double check and, yeah, it still didn't appear after setting isBusy to true – user1818298 Dec 30 '19 at 03:02
  • i test with a similar sample which only replace your `IsAuthenticated` method with a delay,and it works,could you show your `IsAuthenticated` ? or if possible,you could share a simplified example – Leo Zhu Dec 30 '19 at 03:07
  • @LeoZhu-MSFT updated with the method code – user1818298 Dec 30 '19 at 03:17
  • 2
    @user1818298 you could debug on if (!isAuthenticated ) this line,see if it go into it right now after `IsBusy = true;` when you call `OnLogin` method ,if yes, try to use `client.ExecuteAsync` instead of `client.Execute` – Leo Zhu Dec 30 '19 at 03:55
  • @LeoZhu-MSFT i think you're right. i think i need to be doing execute async instead of execute. unfortunately ill have to play around with it tomorrow. thanks for the help! ill be sure to comment back with updates. – user1818298 Dec 30 '19 at 04:04
  • @LeoZhu-MSFT you were right. i had to change from client.Execute to client.ExecuteTaskAsync and it works like a charm. add your comment as an answer and ill mark it. – user1818298 Dec 30 '19 at 21:28
  • @user1818298 ok,i will do it – Leo Zhu Dec 31 '19 at 01:11

2 Answers2

1

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

Leo Zhu
  • 15,726
  • 1
  • 7
  • 23
0

Make sure your viewmodel implements INotifyPropertyChanged then:

    public bool IsBusy
    {
        set { isBusy = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsBusy))); }
        get { return isBusy; }
    }
Adlorem
  • 1,457
  • 1
  • 11
  • 10