MessagingCenter UnSubscribe & Subscribe after Popasync

KathirVelKathirVel USMember ✭✭
edited March 2016 in Xamarin.Forms

Hi,

In our sample application (by using MVVM Pattern), MessagingCenter is not subscribing to the items after unsubscribing and Popasyn()/Harward backkey press in page2.

  1. Page1:-

page1.Xaml.cs
MessagingCenter.Subscribe(this, "displayDialog_Page1_loading", message => {
Device.BeginInvokeOnMainThread(() =>
{
DependencyService.Get().Show("loading");
});
});

  protected override void OnDisappearing()
  {
    base.OnDisappearing();
    MessagingCenter.Unsubscribe<string>(this, "displayDialog_Page1_loading");
    //MessagingCenter.Unsubscribe<string>(this, "displayDialog_Configuration");   
  }

Page1ViewModel.cs

      MessagingCenter.Send<String>("Start", "displayDialog_Page1_loading");
      await Task.Run(async () =>
      {
         // Application functions
      }

2.Page2:-

Navigation.PopAsync(false);

"After PopAsync(false)/ hardware back key press ", the message center is not subscribing to the item to show the progress dialog from page 1.

Kindly advise on this .

Answers

  • AdamPAdamP AUUniversity ✭✭✭✭✭

    @KathirVel - where are you putting the Subscribe functions, are they placed in the OnAppearing function or in the constructor?

    Also if you are just after getting the OnAppearing and OnDisappearing into the ViewModel, I would suggest having a look at this BasePage https://github.com/adamped/xarch-starter/blob/master/Mobile/Base/BasePage.xaml.cs

    and the BaseViewModel. It may be an easier way to implement everything.

    In MVVM messenger is designed for communication between ViewModels, not between ViewModel and Views.

  • NMackayNMackay GBInsider, University mod
    edited March 2016

    @KathirVel

    It's not clear from your sample what your trying to achieve but when you call Page2 OnDisappearing will fire on page1 and your message listener will be unsubscribed so when you go back to page1 nothing will happen because the listener has been unsubscribed.

    The safest way to achieve this is to instantiate listeners in Page and VM ctor's and unsubscribe from the message when the page is popped. OnDisappearing is not a good approach for cleanup and it fires when navigating to another page.

    I use a custom navigation page such as:

    using Xamarin.Forms;
    using PositionFinder.Data.Services.Common;
    
    namespace Foobar.CustomPages
    {
        public class CustomNavigationPage : NavigationPage
        {
            //This ctor is required. This is so  you can call it like normal
            //ex: new CustomNavigationPage(new MyHomePage());
            public CustomNavigationPage(Page content)
                : base(content)
            {
                Init();
            }
    
            private void Init()
            {
                //this.Pushed += (object sender, NavigationEventArgs e) =>
                //{
                //    //here you can handle when pushing a new screen. 
                //    //arg e.Page has the new page to display
    
                //};
    
                this.Popped += (object sender, NavigationEventArgs e) =>
                {
                    var navpage = e.Page as IPageLifetime;
                    if (navpage != null)
                    {
                        // Unregister vm of page, message listener etc
                        navpage.CleanupPage();
                    }
                };
    
            }
        }
    }
    

    Then in the page

    namespace Foobar.View
    {
        [XamlCompilation(XamlCompilationOptions.Compile)]
        public partial class UserProfilePage : IPageLifetime
        {
            public UserProfilePage(UserBio bio)
            {
                InitializeComponent();
                Messenger.Default.Register<UserPosMsg>(this, action => { SetGeoPos(action.GeoPos); });
                ((UserProfileViewModel)this.BindingContext).RefreshCommand.Execute(bio);
            }
    
            public void CleanupPage()
            {
                LoginHistory.Behaviors.Clear(); // You must manually clean behaviors to avoid a memory leak
                Messenger.Default.Unregister<UserPosMsg>(this); // Now safe to unregister code behind listeners
                ((UserProfileViewModel)BindingContext).Cleanup(); // Cleanup vm message listeners, cancel async operations etc
                SimpleIoc.Default.Unregister<UserProfileViewModel>();
            }
    

    This code uses the MVVM Light messenger but the concepts are exactly the same, just a slightly different syntax.

    Hope this helps.

  • NMackayNMackay GBInsider, University mod

    @AdamP

    I'd argue there's no harm in sending a message from a VM to a page with a map (like my sample) when the map doesn't support binding out of the box. These are edge cases though.

  • AdamPAdamP AUUniversity ✭✭✭✭✭

    @NMackay - well I suppose we can make an exception if no binding relationship is possible :)

  • KathirVelKathirVel USMember ✭✭

    @NMackay , Thanks for the MVVM Light Messenger implementation. I will check with MVVM and update.

    @AdamP , In Page1 button command event we have subscribed the Messaging Center .

    Say for Example with login page.
    1. login validation is done in view model and if invalid user information provided then will subscribe the messaging Center to View for showing the DisplayAlert.
    2. if valid informations provided we will navigate to page2 (menu screen) .
    3. From Page2 to Page1 , we used the PopAsync for coming back to page1.

  • KathirVelKathirVel USMember ✭✭

    Hi @adamp, Kindly suggest on this.

  • GeraldVersluisGeraldVersluis NLUniversity ✭✭✭✭

    What are you trying to do, not in technical terms but explain it to me like I'm a two year old?
    Where is the code you are using to subscribe to the message and where are you sending the message?

  • KathirVelKathirVel USMember ✭✭

    @GeraldVersluis ,

    We will show the DisplayAlert from ViewModel to View by using MessagingCenter in Login Screen with Validations.

    After Successful login, we will navigate to menu screen and Unsubscribe the Login MessagingCenter Items in Login Page OnDisappearing Event.

    Once user Press the Logout button in Menu Screen, we will use "Navigation.PopToRootAsync()" to navigate (top of the application page) Login Screen.

    But, After navigating again to Login screen, the same MessagingCenter is not Subscribing to the Validations in Login Screen.

Sign In or Register to comment.