Обычно я использую шаблон Command с формами Xamarin. Недавно пользовательские интерфейсы, над которыми я работал, включают команды, которые вызывают удаленный API, и, пока они это делают, они указывают, что что-то происходит, разными способами. Например, ActivityIndicator должен начать вращаться, когда вызов API возвращает страницу, должна отключить кнопку, et c.
То, что я бы интуитивно закодировал, это asyn c ICommand, например:
VerifyCodeCommand = new Command(async () =>
{
await VerifyCode(_email,_code);
});
в функции VerifyCode я бы изменил свойство, привязанное к свойству IsRunning объекта ActivityIndicator
, на true, await
вызов API, а затем по завершении изменил IsRunning / Visible для ActivityIndicator
обратно к ложному. Например, вот так: Другой пример показывает состояние сбоя API (например: красные предупреждения), а затем сбрасывает его непосредственно перед вызовом API.
К сожалению, это не работает, как и установка связанного свойства Device.BeginInvokeOnMainThread
, поскольку (предположительно) ICommand удерживает поток пользовательского интерфейса (?). В этом простом случае я устанавливаю свойство на true
в команде, затем Task.Run
оставшуюся часть тела функции, то есть вызов API и сброс индикатора, например:
Sending = true;
(VerifyCodeCommand as Command).ChangeCanExecute();
await Task.Run(async () =>
{
try
{
// await api call here
}
catch (Exception ex)
{
App.TrackError(ex, "Login", "VerifyCode API call failed.");
}
finally
{
Sending = false;
(VerifyCodeCommand as Command).ChangeCanExecute();
}
});
}
Необходим ли этот подход или мне не хватает какой-то функциональности в Xamarin (Forms)? Если всегда необходимо обновлять пользовательский интерфейс таким образом, что было бы разумным подходом для этого? Например, должны ли команды всегда иметь две фактические лямбды, одну для настройки начального состояния пользовательского интерфейса, другую для фонового вызова? Почему здесь не работает простой однопоточный асинхронный c подход - вызов API все-таки ожидается.
Я полагаю, почему вопрос сводится к следующему: почему это вызывает асинхронный c Вызов API с ожиданием в основном потоке выглядит так, как будто основной поток не освобождается для обновления пользовательского интерфейса (похоже, что жизненный цикл пользовательского интерфейса Xamarin вводит некоторые ограничения), и какое стандартное решение для этого?