У меня есть страница, на которой я получаю данные из API в методе OnAppearing:

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();
}

Это работает нормально, но на той же странице у меня есть 2 обработчика событий, где мне также нужно сделать тот же вызов API. Так что было бы лучше переместить это в функцию. Но как я могу это сделать, ведь обработчики событий нельзя сделать асинхронными?

Так что в идеале у меня было бы OnAppearing вот так:

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

    base.OnAppearing();
}

И затем обработчик событий, который вызывает тот же метод:

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

Как я могу это сделать?

1
John 3 Янв 2018 в 15:44

2 ответа

Лучший ответ

Я бы пошел по этому пути:

Извлеките ваш вызов api в один метод:

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

Этот метод можно вызвать в OnAppearing

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

    listView.ItemsSource = _footmarks;

    base.OnAppearing();
}

И в EventHandler это можно использовать точно так же. Единственное изменение - пометить обработчик ключевым словом async.

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

    listView.ItemsSource = _footmarks;
    listView.EndRefresh();
}
1
tequila slammer 3 Янв 2018 в 13:15

Так что было бы лучше переместить это в функцию.

Разумным выбором является извлечение повторяющейся функции в ее собственную функцию.

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

Это позволит вам вызывать его во всем зависимом классе.

Вам даже следует подумать о том, чтобы извлечь его в отдельный сервис, который можно будет повторно использовать в других частях приложения.

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

Но как я могу это сделать, ведь обработчики событий нельзя сделать асинхронными?

Обработчики событий можно сделать асинхронными.

Ссылка Async / Await - лучшие практики асинхронного программирования

Избегайте async void за исключением фактических обработчиков событий.

OnAppearing(), к сожалению, не обработчик событий, а реальный виртуальный метод.

Однако событие Appearing возникает после того, как платформа вызывает OnAppearing, что означает, что вы можете подписаться на событие там и выполнять свои асинхронные операции в фактическом обработчике событий для этого события, когда поднял.

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();
}
1
Nkosi 3 Янв 2018 в 14:38