rid00z / FreshMvvm

FreshMvvm is a super light Mvvm Framework designed specifically for Xamarin.Forms. It's designed to be Easy, Simple and Flexible.
Apache License 2.0
596 stars 172 forks source link

[Question] Page model lifecycle events #302

Closed neilt6 closed 4 years ago

neilt6 commented 4 years ago

Is there a way to detect when a page model is navigated away from and removed from the stack besides ViewIsDisappearing? I need a way to clean up and dispose of some objects, but ViewIsDisappearing is also called when the app is backgrounded. In Caliburn.Micro, I used DeactivateAsync and observed the bool close parameter to determine if the view model was being popped.

neilt6 commented 4 years ago

@rid00z Any thoughts on this? I've done some additional experiments, and it looks like ViewIsDisappearing is called a lot more frequently on Android than on iOS.

neilt6 commented 4 years ago

I managed to solve this with the following attached behavior and interface:

using System;
using Xamarin.Forms;

namespace MobileTestApp
{
    interface IHandleViewPopped
    {
        #region Methods

        void ViewPopped(object sender, NavigationEventArgs e);

        #endregion
    }

    class NotifyOnPoppedBehavior : Behavior<Page>
    {
        #region Fields

        Page m_Page;

        #endregion

        #region Protected Methods

        protected override void OnAttachedTo(Page bindable)
        {
            //Call the base implementation
            base.OnAttachedTo(bindable);

            //Set up delayed attachment
            m_Page = bindable;
            m_Page.Appearing += Page_Appearing;
        }

        #endregion

        #region Event Handlers

        private void Page_Appearing(object sender, EventArgs e)
        {
            //Register for popped events from the parent navigation page
            if (m_Page.Parent is NavigationPage navigationPage)
            {
                navigationPage.Popped += NavigationPage_Popped;
            }
            m_Page.Appearing -= Page_Appearing;
        }

        private void NavigationPage_Popped(object sender, NavigationEventArgs e)
        {
            //Handle the popped event
            if (e.Page == m_Page)
            {
                NavigationPage navigationPage = sender as NavigationPage;
                if (m_Page.BindingContext is IHandleViewPopped pageModel)
                {
                    pageModel.ViewPopped(sender, e);
                }
                navigationPage.Popped -= NavigationPage_Popped;
            }
        }

        #endregion
    }
}