1

I have a page where I retrieve data from an API in the OnAppearing method:

protected override async void OnAppearing()
{
    var content = await _client.GetStringAsync(Url);
    var footmarks = JsonConvert.DeserializeObject<List<Footmark>>(content);
    _footmarks = new ObservableCollection<Footmark>(footmarks);
    listView.ItemsSource = _footmarks;

    base.OnAppearing();
}

This works fine, but on the same page I have 2 event handlers where I also need to make the same API call. So it would be best to move this to a function. But how can I do this, because the event handlers cannot be made async?

So ideally I would have OnAppearing like this:

protected override async void OnAppearing()
{
    listView.ItemsSource = GetFootmarks();

    base.OnAppearing();
}

And then an event handler which calls the same method:

void Handle_Refreshing(object sender, System.EventArgs e)
{
    listView.ItemsSource = GetFootmarks();
    listView.EndRefresh();
}

How can I do this?

2 Answers 2

1

I would go that way:

Extract your api call into a single method:

async Task<List<Footmark>> GetFootMarksAsync()
{
    var content = await _client.GetStringAsync(Url);
    return JsonConvert.DeserializeObject<List<Footmark>>(content);
}

This method can be called in OnAppearing

protected override async void OnAppearing()
{
    _footmarks = new ObservableCollection<Footmark>(await GetFootMarksAsync());

    listView.ItemsSource = _footmarks;

    base.OnAppearing();
}

And in the EventHandler it can be used the same way. Only change is to mark the handler with the async keyword.

async void Handle_Refreshing(object sender, System.EventArgs e)
{
    _footmarks = new ObservableCollection<Footmark>(await GetFootMarksAsync());

    listView.ItemsSource = _footmarks;
    listView.EndRefresh();
}
Sign up to request clarification or add additional context in comments.

Comments

1

So it would be best to move this to a function.

Extracting the repeated functionality into its own function is a wise choice.

async Task<ObservableCollection<Footmark>> GetFootmarks() {
    var json = await _client.GetStringAsync(Url);
    return JsonConvert.DeserializeObject<ObservableCollection<Footmark>>(json);
}

this will allow you to call it throughout the dependent class.

You should even consider extracting it out into its own service that can be reused in other parts of the application.

public interface IFoomarkService {
    Task<ObservableCollection<Footmark>> GetFootmarks();
}

But how can I do this, because the event handlers cannot be made async?

Event handlers can be made async.

Reference Async/Await - Best Practices in Asynchronous Programming

Avoid async void with the only exception being actual event handlers.

OnAppearing() unfortunately is not an event handler but an actual virtual method.

However the Appearing event is raised after the framework invokes OnAppearing, which means you can subscribe to the event there and perform your async operations in the actual event handler for that event when raised.

protected override void OnAppearing() {
    this.Appearing += Page_Appearing; //Subscribe to event
    base.OnAppearing();
}

protected async void Page_Appearing(object sender, EventArgs args) {
    listView.ItemsSource = await GetFootmarks(); //get data asynchronously
    //this.Appearing -= Page_Appearing; //Unsubscribe (OPTIONAL but advised)
}

protected async void Handle_Refreshing(object sender, System.EventArgs e) {
    listView.ItemsSource = await GetFootmarks(); //get data asynchronously
    listView.EndRefresh();
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.