webentwicklung-frage-antwort-db.com.de

Wie kann ich mit Xamarin.Forms auf die modale Entlassung warten?

Wie verwende ich Xamarin.Forms, um eine asynchrone Methode zu erstellen, die darauf wartet, dass das Formular geschlossen wird? Wenn ich benutze

await Navigation.PushModalAsync(page);

sobald die Animation beendet ist, wird sie zurückgegeben, nicht wenn die Seite geschlossen wird.

Ich möchte eine modale Task-SignInAsync-Methode erstellen, die true zurückgibt, wenn die Anmeldung erfolgreich ist.

16
Jamey McElveen

Sie können dies tun, indem Sie auf Ihrer Anmeldeseite ein Ereignis auslösen und das Ereignis abhören, bevor Sie fortfahren, aber Sie möchten die volle TAP-Unterstützung, und ich unterstütze Sie dort. Hier ist eine einfache, aber funktionierende 2-Seiten-App, die genau dies tut. Natürlich möchten Sie die benutzerdefinierte Unterklasse ContentPage verwenden und die richtigen Methoden anstelle meiner schnellen Commands verwenden, aber Sie haben die Idee, und ich muss nicht mehr tippen.

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

Der kleinere Nachteil ist, dass Task<bool> vor dem Ende der Pop-Modal-Animation zurückgegeben wird.

  1. einfach zu reparieren
  2. nur ein Problem, wenn Sie auf dieses Ergebnis warten, um eine neue modale Page zu verschieben. Ansonsten, meh, mach einfach weiter.
21

OnAppearing überschreiben

Erstens ist es erwähnenswert, dass das einfache Überschreiben von OnAppearing in der aufrufenden Seite unter vielen Umständen ausreichen kann. 

protected override void OnAppearing()
{
    base.OnAppearing();
    ...
    // Handle any change here from returning from a Pushed Page
}

(Beachten Sie, dass die OnDisappearing-Überschreibung der gepufferten Seite after die OnAppearing des Aufrufers genannt wird - scheint mir ein wenig rückwärts zu sein!)


AwaitableContentPage

Zweitens ... das ist meine Meinung zu @Chad Bonthuys Antwort:

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

Und dann nenne es so:

SettingsPage sp = new SettingsPage();
await Navigation.PushAsync(sp);
await sp.PageClosedTask; // Wait here until the SettingsPage is dismissed
13
noelicus

In meiner Implementierung habe ich verwendet: 

await navigation.PopModalAsync();

Vollständiges Beispiel:

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);
        }
    }
1
Chad Bonthuys

Ich dachte nur, ich würde zu diesem Beitrag beitragen, obwohl es schon eine Weile her ist, seit es gefragt und beantwortet wurde. Ich habe auf der Antwort von @noelicus aufgebaut. Ich wollte eine generische Methode, um dies in mehreren Situationen zu tun, sodass die Aufgabe nicht nur bool, sondern alles zurückgeben muss. Dann mit Generika:

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

Auf der Seite, die Sie als modal ausführen möchten, können Sie Folgendes tun:

public partial class NewPerson : AwaitableContentPage<Person>

und wenn Sie fertig sind, machen Sie einfach:

            base.PageResult = newPerson; // object you created previously
            await base.Navigation.PopAsync();

Verwenden Sie dann eine Erweiterungsmethode, um die Verwendung zu vereinfachen:

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

Das ist alles. Nun, in Ihrem Code, auf jeder Seite, auf der Sie dies verwenden möchten, endet die Syntax einfach wie folgt:

            Person newPerson = await Navigation.GetResultFromModalPage<string>(new NewPersonCreatePage());

            if (newPerson != null)
                UseNewPersonCreatedByOtherPage();

Hoffe das hilft!

1
David