Как я могу ожидать отклонения модальной формы с помощью Xamarin.Forms?
Использование Xamarin.Forms, как я могу использовать метод async, ожидающий отклонения формы? Если я использую
await Navigation.PushModalAsync(page);
он вернется после завершения анимации, когда страница не будет удалена.
Я хочу создать модальный метод TaskInAsync Task, который возвращает true, если вход успешно завершен.
Ответы
Ответ 1
Вы можете сделать это, инициировав событие на своей странице входа и прослушав это событие, прежде чем продолжить, но вы хотите, чтобы полная поддержка TAP и я второй вам там. Вот простое, но работающее 2-страничное приложение, которое делает именно это. Очевидно, вы захотите использовать ContentPage
пользовательский подкласс и иметь правильные методы вместо моих быстрых Command
s, но вы получите эту идею, и это избавит меня от ввода.
public static Page GetFormsApp ()
{
NavigationPage navpage = null;
return navpage = new NavigationPage (new ContentPage {
Content = new Button {
Text = "Show Login dialog",
Command = new Command (async o => {
Debug.WriteLine ("Showing sign in dialog");
var result = await SignInAsync (navpage);
Debug.WriteLine (result);
})
}
});
}
static Task<bool> SignInAsync (NavigationPage navpage)
{
Random rnd = new Random ();
var tcs = new TaskCompletionSource<bool> ();
navpage.Navigation.PushModalAsync (new ContentPage {
Content = new Button {
Text = "Try login",
Command = new Command ( o => {
var result = rnd.Next (2) == 1;
navpage.Navigation.PopModalAsync ();
tcs.SetResult (result);
})
}
});
return tcs.Task;
}
Небольшой недостаток заключается в том, что Task<bool>
возвращается до конца анимации pop popal, но это:
- легко исправить
- только проблема, если вы ожидаете этого результата, чтобы нажать новый модальный
Page
. В противном случае, meh, просто продолжайте.
Ответ 2
Override OnAppearing
Во-первых, стоит отметить, что просто переопределение OnAppearing
на вызывающей странице может быть достаточно во многих случаях.
protected override void OnAppearing()
{
base.OnAppearing();
...
// Handle any change here from returning from a Pushed Page
}
(обратите внимание, что переадресованная страница OnDisappearing
override вызывается после вызова OnAppearing
- кажется немного назад мне!)
AwaitableContentPage
Во-вторых... это мой ответ на @Chad Bonthuys:
public class AwaitableContentPage : ContentPage
{
// Use this to wait on the page to be finished with/closed/dismissed
public Task PageClosedTask { get { return tcs.Task; } }
private TaskCompletionSource<bool> tcs { get; set; }
public AwaitableContentPage()
{
tcs = new System.Threading.Tasks.TaskCompletionSource<bool>();
}
// Either override OnDisappearing
protected override void OnDisappearing()
{
base.OnDisappearing();
tcs.SetResult(true);
}
// Or provide your own PopAsync function so that when you decide to leave the page explicitly the TaskCompletion is triggered
public async Task PopAwaitableAsync()
{
await Navigation.PopAsync();
tcs.SetResult(true);
}
}
И затем назовите его так:
SettingsPage sp = new SettingsPage();
await Navigation.PushAsync(sp);
await sp.PageClosedTask; // Wait here until the SettingsPage is dismissed
Ответ 3
В моей реализации я использовал:
await navigation.PopModalAsync();
Полный пример:
private INavigation navigation;
public LoginPageModel(INavigation navigation, LoginPage loginPage)
{
this.navigation = navigation;
this.loginPage = loginPage;
}
public bool IsValid { get; set; }
protected async void ExecuteLoginCommand()
{
var loginResult = await AuthenticationHelper.Authenticate(Email, Password);
var isValid = false;
if (loginResult != null)
{
isValid = true;
}
//return isValid;
AuthenticationResult(isValid);
}
private async void AuthenticationResult(bool isValid)
{
if (isValid)
{
Debug.WriteLine("Logged in");
await navigation.PopModalAsync();
}
else
{
Debug.WriteLine("Failed" + email + password);
await loginPage.DisplayAlert("Authentication Failed", "Incorrect email and password combination","Ok", null);
}
}
Ответ 4
Просто подумал, что буду способствовать этому, хотя прошло некоторое время с тех пор, как его спросили и ответили. Я основывался на ответе @noelicus. Мне нужен общий способ сделать это с несколькими ситуациями, поэтому задача должна иметь возможность возвращать не только bool, но и все. Затем, используя generics:
public class AwaitableContentPage<T> : ContentPage
{
// Use this to wait on the page to be finished with/closed/dismissed
public Task<T> PageClosedTask => tcs.Task;
// Children classes should simply set this to the value being returned and pop async()
protected T PageResult { get; set; }
private TaskCompletionSource<T> tcs { get; set; }
public AwaitableContentPage()
{
tcs = new TaskCompletionSource<T>();
}
protected override void OnDisappearing()
{
base.OnDisappearing();
tcs.SetResult(PageResult);
}
}
Теперь, на странице, которую вы хотите запустить как модальный, вы можете сделать:
public partial class NewPerson : AwaitableContentPage<Person>
и когда это будет сделано, просто выполните:
base.PageResult = newPerson; // object you created previously
await base.Navigation.PopAsync();
Затем, чтобы сделать его очень простым в использовании, используйте метод расширения:
public static class ExtensionMethods
{
async public static Task<T> GetResultFromModalPage<T>(this INavigation nav, AwaitableContentPage<T> page)
{
await nav.PushAsync(page);
return await page.PageClosedTask;
}
Это все. Теперь в вашем коде на любой странице, где вы хотите использовать это, синтаксис заканчивается следующим образом:
Person newPerson = await Navigation.GetResultFromModalPage<string>(new NewPersonCreatePage());
if (newPerson != null)
UseNewPersonCreatedByOtherPage();
Надеюсь, это поможет!