Ways to wait for result from a Page / Modal

ReinVReinV BEMember ✭✭
edited March 2016 in Xamarin.Forms

Hello everyone,

I'm trying to figure out an elegant / effective way to wait for a result from a Page or Modal before continuing

I have tried using:

Events:

public class SomePage : ContentPage
{
    public event EventHandler<ResultsEventHandlerArgs> OnResults;

    public SomePage ()
    {
              //...
        }
}


// Somewhere in the application

SomePage page = new SomePage ();

page.OnResults += async (object sender, ResultsEventHandlerArgs e) => {
    await Navigation.PopModalAsync();
    //Do something with the results in e
};

await Navigation.PushModalAsync (page);

Pro's:

  • Logic is not coupled
  • Can use that (modal) Page 'anywhere'

Con's:

  • Forgetting to unsubscribe from the event can cause the page to stay in memory longer than expected

TaskCompletionSource:

In our application logic after logging in some users had to choose some options before continuing to the 'main' app and others didn't.
So I used some thing like

public class App : Application
{
     public App()
     {
           //Some logic

          if(ExtraOptions)
          {
               TaskCompletionSource tcs = new TaskCompletionSource();
               MainPage = new SomePage(tcs);
               //In the SomePage after the options are chosen -> tcs.SetResult();
               var task = await tcs.Task;
               var result = task.Result;
               task.Dispose();
               //Do something with the result
          }

          //Load the 'Main' app
         MainPage = new MasterDetailPage();
     }
}

And I tried combinations of both events and TaskCompletionSource, but I'm unsure if this is an acceptable way to approach this problem.

This is written from memory so there might be some typo's etc. in the examples above

Are there other ways I can take or improvements I can make to achieve this behaviour (The waiting for a result before continuing) ?

Best Answer

Answers

  • ReinVReinV BEMember ✭✭
    edited March 2016

    @chrfalch said:
    MessagingCenter will solve it. Subscribe before calling PushModalAsync, send a message from the modal page when it's done - remember to unsubscribe when the message has been handled. This is the most decoupled and clean solution.

    Is there an advantage in using the MessagingCenter instead of EventHandler<> ?

    Looks really similar

    EDIT

    Looking more into it I think i see the advantage:

    EventHandler

    Class1 <-> Class2

    MessagingCenter

    Class1 <-> MessagingCenter <-> Class2

    So they actualy don't know anything about eachother but only about the MessagingCenter itself.

    Would this prevent issues with object being kept alive if one forgets to unsubscribe from events ?

    (I know this shouldn't happen but we are human after all)

  • ChristianFalchChristianFalch NODeveloper Group Leader ✭✭✭

    Yes, that's the great thing with messagingcenter. You can of course use events and unset them correctly.

  • ReinVReinV BEMember ✭✭

    Thank you for your time

  • DamienDoumerDamienDoumer USMember ✭✭

    @ReinV Here is a solution which makes code more readable than the MessagingCenter:

    You can do this by calling an event from the page's OnDisapearing method, this event can then be subscribed by the navigation service which you create, and you can then use the "TaskCompletionSource" to wati until your page finishes its work and then complete the task.

    For more details about accomplishing this, you can check this blog post: **https: //doumer.me/xamarin-forms-tips-navigate-to-a-page-and-wait-results/ **

    Here is an overview of the navigation service you should use:

    public async Task<T> NavigateToModal<T>(string modalName)
        {
            var source = new TaskCompletionSource<T>();
            if (modalName == nameof(NewItemPage))
            {
                var page = new NewItemPage();
                page.PageDisapearing += (result) =>
                {
                    var res = (T)Convert.ChangeType(result, typeof(T));
                    source.SetResult(res);
                };
                await App.Current.MainPage.Navigation.PushModalAsync(new NavigationPage(page));
            }
            return await source.Task;
        }
    

    Here is how you use it:

    var item = await new SimpleNavigationService().NavigateToModal<Item>(nameof(NewItemPage)); Items.Add(item);

    This solution makes your code cleaner and more readable than subscribing to messaging events here and there...

Sign In or Register to comment.