{"action":"created","issue":{"url":"https://api.github.com/repos/PrismLibrary/Prism/issues/142","labels_url":"https://api.github.com/repos/PrismLibrary/Prism/issues/142/labels{/name}","comments_url":"https://api.github.com/repos/PrismLibrary/Prism/issues/142/comments","events_url":"https://api.github.com/repos/PrismLibrary/Prism/issues/142/events","html_url":"https://github.com/PrismLibrary/Prism/issues/142","id":106236808,"number":142,"title":"[XF] Add extended navigation awareness when Page.Disappearing/Appearing is raised","user":{"login":"joacar","id":439028,"avatar_url":"https://avatars.githubusercontent.com/u/439028?v=3","gravatar_id":"","url":"https://api.github.com/users/joacar","html_url":"https://github.com/joacar","followers_url":"https://api.github.com/users/joacar/followers","following_url":"https://api.github.com/users/joacar/following{/other_user}","gists_url":"https://api.github.com/users/joacar/gists{/gist_id}","starred_url":"https://api.github.com/users/joacar/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/joacar/subscriptions","organizations_url":"https://api.github.com/users/joacar/orgs","repos_url":"https://api.github.com/users/joacar/repos","events_url":"https://api.github.com/users/joacar/events{/privacy}","received_events_url":"https://api.github.com/users/joacar/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/PrismLibrary/Prism/labels/XF","name":"XF","color":"5319e7"}],"state":"closed","locked":false,"assignee":null,"milestone":null,"comments":3,"created_at":"2015-09-13T20:00:48Z","updated_at":"2016-01-15T20:09:15Z","closed_at":"2016-01-15T20:09:15Z","body":"In certain cases a page can be dismissed without the dismissal originating from the view model. For example when hardware back button is pressed on Android devices or back button is pressed on iOS.\r\n\r\nIn this cases the `Page.Appearing` and `Page.Disappearing` is raised and these events should be delegated to the view models bound to respective views.\r\n\r\nA way to accomplish this is via an attached property (like `ViewModelLocator.AutoWireViewModel`)\r\n\r\nExample\r\n````c#\r\n/// <summary>\r\n    /// Class providing property for makeing view modal aware of page life cycle changes.\r\n    /// \r\n    /// Cred goes to https://github.com/XLabs/Xamarin-Forms-Labs/issues/542\r\n    /// </summary>\r\n    /// <para>\r\n    /// Setting <see cref=\"IsNavigationAwareProperty\"/> to <c>true</c> provides delegating of the events <see cref=\"Page.Appearing\"/> and <see cref=\"Page.Disappearing\"/> \r\n    /// to a view model implementing <see cref=\"INavigationAware\"/> interface.\r\n    /// </para>\r\n    public class NavigationAwareUtils\r\n    {\r\n        public static BindableProperty IsNavigationAwareProperty = BindableProperty\r\n            .CreateAttached<NavigationAwareUtils, bool>(\r\n                bindable => GetIsNavigationAware(bindable),\r\n                false,\r\n                BindingMode.OneWay,\r\n                null,\r\n                OnAppearingChanged);\r\n\r\n        public static bool GetIsNavigationAware(BindableObject bo)\r\n        {\r\n            return (bool)bo.GetValue(IsNavigationAwareProperty);\r\n        }\r\n\r\n        public static void SetIsNavigationAware(BindableObject bo, bool value)\r\n        {\r\n            bo.SetValue(IsNavigationAwareProperty, value);\r\n        }\r\n\r\n        private static void OnAppearingChanged(BindableObject bindable, bool oldvalue, bool newvalue)\r\n        {\r\n            var page = bindable as Page;\r\n            if (page == null) return;\r\n\r\n            if (oldvalue)\r\n            {\r\n                page.Appearing -= OnAppearing;\r\n                page.Disappearing -= OnDisappearing;\r\n            }\r\n            if (newvalue)\r\n            {\r\n                page.Appearing += OnAppearing;\r\n                page.Disappearing += OnDisappearing;\r\n            }\r\n        }\r\n\r\n        /// <summary>\r\n        /// Delegate calls to <see cref=\"Page.Appearing\"/> to <see cref=\"INavigationAware.OnNavigatedTo\"/>\r\n        /// </summary>\r\n        /// <para>\r\n        /// The <see cref=\"NavigationParameters\"/> sent to <see cref=\"INavigationAware.OnNavigatedTo\"/> is <see cref=\"NavigationParametersExtensions.Appearing\"/>\r\n        /// </para>\r\n        /// <param name=\"sender\"></param>\r\n        /// <param name=\"e\"></param>\r\n        private static void OnAppearing(object sender, EventArgs e)\r\n        {\r\n            var page = sender as Page;\r\n            if (page == null) return;\r\n\r\n            var navigationAware = page.BindingContext as INavigationAware;\r\n            if (navigationAware == null)\r\n            {\r\n                page.Appearing -= OnAppearing;\r\n                return;\r\n            }\r\n\r\n            navigationAware.OnNavigatedTo(NavigationParametersExtensions.Appearing);\r\n        }\r\n\r\n        /// <summary>\r\n        /// Delegate calls to <see cref=\"Page.Disappearing\"/> to <see cref=\"INavigationAware.OnNavigatedFrom\"/>\r\n        /// </summary>\r\n        /// <para>\r\n        /// The <see cref=\"NavigationParameters\"/> sent to <see cref=\"INavigationAware.OnNavigatedFrom\"/> is <see cref=\"NavigationParametersExtensions.Disappearing\"/>\r\n        /// </para>\r\n        /// <param name=\"sender\"></param>\r\n        /// <param name=\"e\"></param>\r\n        private static void OnDisappearing(object sender, EventArgs e)\r\n        {\r\n            var page = sender as Page;\r\n            if (page == null) return;\r\n\r\n            var navigationAware = page.BindingContext as INavigationAware;\r\n            if (navigationAware == null)\r\n            {\r\n                page.Disappearing -= OnDisappearing;\r\n                return;\r\n            }\r\n\r\n            navigationAware.OnNavigatedFrom(NavigationParametersExtensions.Disappearing);\r\n        }\r\n    }\r\n````\r\n\r\nThis example utilize the existing interface `INavigationAware` with \"fixed\" navigation parameters (and extension methods on `NavigationParameters`) sent to easily distinguish when it is a delegated call.\r\n\r\nPersonally I would like to see these calls implemented as async and perhaps add two methods to the `INavigationAware` interface for `OnAppearingAsync` and `OnDisappearingAsync`.\r\n\r\nThoughts?"},"comment":{"url":"https://api.github.com/repos/PrismLibrary/Prism/issues/comments/172073966","html_url":"https://github.com/PrismLibrary/Prism/issues/142#issuecomment-172073966","issue_url":"https://api.github.com/repos/PrismLibrary/Prism/issues/142","id":172073966,"user":{"login":"brianlagunas","id":835562,"avatar_url":"https://avatars.githubusercontent.com/u/835562?v=3","gravatar_id":"","url":"https://api.github.com/users/brianlagunas","html_url":"https://github.com/brianlagunas","followers_url":"https://api.github.com/users/brianlagunas/followers","following_url":"https://api.github.com/users/brianlagunas/following{/other_user}","gists_url":"https://api.github.com/users/brianlagunas/gists{/gist_id}","starred_url":"https://api.github.com/users/brianlagunas/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/brianlagunas/subscriptions","organizations_url":"https://api.github.com/users/brianlagunas/orgs","repos_url":"https://api.github.com/users/brianlagunas/repos","events_url":"https://api.github.com/users/brianlagunas/events{/privacy}","received_events_url":"https://api.github.com/users/brianlagunas/received_events","type":"User","site_admin":false},"created_at":"2016-01-15T20:09:15Z","updated_at":"2016-01-15T20:09:15Z","body":"I did a little research and this is a source of memory leaks.  The events are never unhook and the attached property retains a ref to the page which roots it.  Having said that, we will not be adding this to Prism for now."}}