I have been trying to dispose a ViewElement
/View
when the Page
displaying it is no longer on top of the NavigationStack
in Xamarin Forms.
It seems there is a new effect called LifecycleEffect
from Xamarin Community Toolkit that would be able to do just that, but the Unloaded
event does not fire when a new page is placed on top of the NavigationStack
(and therefore the view-element will not be removed and not trigger the event).
Does anybody know and event that I can bind to on a View
that allows me to determine it is not displaying, but is still in the NavigationStack
somewhere?
I really want the View
to do this itself and not use the Page
for that.
Thanks in advance :)
AFAIK no platform does that, because it is a bit expensive (for something that is almost never needed): a method would have to be executed on every visual element on the screen, every time a page hides or shows.
The only solution (I am aware of) is to have this view add an "event handler" to the page it is in, and then have the page's OnDisappearing invoke that event handler. Define an Interface that exposes an "AddActionOnDisappearing" method. Implement that interface on pages that might have this view.
First Version: a hand-coded solution:
public interface IActionOnDisappearing
{
void AddActionOnDisappearing(Action action)
{
}
}
public partial class MyPage : IActionOnDisappearing
{
...
public void AddActionOnDisappearing(Action action)
{
... remember the action somewhere ...
}
protected override void OnDisappearing()
{
... call that action or event handler ...
...
}
}
public partial class MySpecialView
{
// constructor
void MySpecialView(IActionOnDisappearing owningPage)
{
...
TellMeThePage(owningPage);
}
public void TellMeThePage(IActionOnDisappearing owningPage)
{
owningPage.AddActionOnDisappearing( () =>
... whatever you need to do ...
);
}
}
Note that the view constructor takes a parameter.
An alternative is to let XAML build the views on the page, give that view an x:Name
attribute, then in page's constructor, after InitializeComponent, connect the two:
public partial class MyPage : IActionOnDisappearing
{
// constructor
void MyPage()
{
InitializeComponent();
this.NameOfMySpecialView.TellMeThePage(this);
...
}
}
public partial class MySpecialView
{
// constructor
void MySpecialView()
{
...
}
public void TellMeThePage(IActionOnDisappearing owningPage)
...
}
I've left out details of the event handler that MyPage would need. Google for information on that topic.
Second Version
The solution above requires the Page to be aware it has such a View. And to give that View a name. And add a code line to the constructor.
To make it easier to code, define this somewhere:
public static void TellMySpecialDescendents(Page owner)
{
... search all children and their children
... any that are of type `MySpecialView`, call
((MySpecialView)child).TellMeThePage(owner);
}
Define class BasePage
, that implements IActionOnDisappearing
. Any class that might have such a view, inherit from BasePage.
And call TellMySpecialDescendents
from constructor of such a page. After InitializeComponent
of course.
If you have more than one such view-type that needs to know about its owner, define an Interface:
public interface IViewOnDisappearing
{
void TellMeThePage(IActionOnDisappearing owningPage);
}
public partial class MySpecialView : IViewOnDisappearing
...
And replace MySpecialView
uses with IViewOnDisappearing
.