Search code examples
eventsxamarin.formscallbackondisappearing

How to unsubscribe from Event after a Page disappear


From a viewModel of a page which displays DATA, I need to display a SecondaryPage, with a subset of those DATA. So when the button is clicked, I apply filter to the DATA and call the SecondaryPage. I pass a callback to reset the filters when then secondPage Disappear :

private async Task levelClickedAction(object arg)
{
    var level = arg as Observable<string>;
    if (level == null) return;
    
    // Unselect the clicked item
    LevelClicked = null;

    isHidden = true; // Prevent from updating primary page

    // Apply filter to the data
    wordDictionary.SetReviewPlanFilter( Reviews.IndexOf(level) );

    // Create secondary page, setup callback and display it
    var page = new SecondaryPage();
    page.OnDisappearingEvent += ResertFilters;

    await Application.Current.MainPage.Navigation.PushModalAsync(new NavigationPage(page));
}

private void ResetFilters(object sender, object e)
{
    isHidden = false;
    wordDictionary.ResetReviewPlanFilter();
}

My questions are:

  • Do I need to unsubscribe from the OnDisappearingEvent to ensure that the SecondaryPage is correctly disposed ? It seems that, yes, I do because of the strong reference of the handler and the longer lifetime of my mainpage. Correct ?
  • So how to do it, where and when ?

I have tried to use .ContinueWith() after PushModalAsync(new NavigationPage(page)) but it is fired immediately...

And the proble is that in the ResetFilters proc, I do not know the page anymore... I could make a field instead of the var page then :

private WordList page;
...
private void ResetFilters(object sender, object e)
{
    isHidden = false;
    page.OnDisappearingEvent -= ResetFilters;
    page = null;
    wordDictionary.ResetReviewPlanFilter();
}

But it looks uggly ... Is there a more beautifull/straighforward way ?

Thanks for your suggestions.


Solution

  • Ok, I found a far better way, which I was looking for. It doesn't need to adapt the targetted SecondaryPage

    I made an interface for my ViewModel:

    public interface IReturnCallback
    {
        Action OnReturnCallback {get; set; }
    }
    

    And I adapt the .xaml.cs file of my calling page like this:

    protected override void OnAppearing()
    {
        // Invoke callback if any
        ((IReturnCallback)BindingContext)?.OnReturnCallback?.Invoke();
    
        base.OnAppearing();
    }
    

    So whenever I have to execute code when I come back from one page, I assign it in OnReturnCallback just before to call the SecondaryPage like this :

    private async Task levelClickedAction(object arg)
    {
        var level = arg as Observable<string>;
        if (level == null) return;
        
        // Unselect the clicked item
        LevelClicked = null;
    
        isHidden = true; // Prevent from updating primary page
    
        // Apply filter to the data
        wordDictionary.SetReviewPlanFilter( Reviews.IndexOf(level) );
    
        // Create secondary page, setup callback and display it
        if (page == null) page = new WordList();
        OnReturnCallback = () => {
            isHidden = false;
            wordDictionary.ResetReviewPlanFilter();
            OnReturnCallback = null;
        };
    
        await Application.Current.MainPage.Navigation.PushModalAsync(new NavigationPage(page));
    }
    

    Don't forget to reset OnReturnCallback so it is only called once.

    Any comment ?