Xamarin.forms: [Bug] Shell - OnAppearing not executing

Created on 11 Jun 2019  ·  32Comments  ·  Source: xamarin/Xamarin.Forms

Description

I have overrided the OnAppearing (and OnDisappearing) methods in the AppShell of a new project. The OnAppearing never seems to execute. Shell inherits from Page, so it should probably use OnAppearing. This would be nice for executing code that needs to be await'ed and cannot be in the constructor.

Steps to Reproduce

  1. Create a new Xamarin Forms Project and select the Shell template
  2. Open AppShell.xaml.cs
  3. Add an override for OnAppearing
  4. Add code in the OnAppearing to write to the Console
  5. Set breakpoint
  6. Run the project

Expected Behavior

The breakpoint should be hit or at least the Console WriteLine should be visible in the output window.

Actual Behavior

The breakpoint is never hit and the text does not show up in the output window.

Basic Information

  • Version with issue: 4.0.0.482894
  • Last known good version: N/A
  • IDE: Visual Studio 2019 for Windows 16.1.2
  • Platform Target Frameworks:

    • iOS: 12.10.0.153

    • Android: N/A

    • UWP: N/A

  • Android Support Library Version: N/A
  • Nuget Packages: Just what comes with the template
  • Affected Devices:

Screenshots

Reproduction Link

https://github.com/seansparkman/ShellNavigationExample/blob/master/ShellNavigationRegistration/ShellNavigationRegistration/AppShell.xaml.cs#L27

Also resolve the issue with OnNavigated not firing
https://github.com/xamarin/xamarin.forms/issues/6486#issuecomment-540595443

shell 2 help wanted high impact bug up-for-grabs

Most helpful comment

Is this bug going to be fixed? Because if shell inherits from Page but does not implement OnAppearing and also lets the user override it without it being called. Its really strange behavior and therefor Shell should not inherit from Page?

Especially if you use 3rd party frameworks that relay on OnAppearing to call WhenActivated/WhenDeactivted for example (ReactiveUI). Took us some time to figure out that OnAppearing is not being called.

All 32 comments

same to me :/ current version of forms

Hi, There is a PR here to add appearing and disappearing methods https://github.com/xamarin/Xamarin.Forms/pull/6527

thank you.

Am So., 16. Juni 2019 um 00:31 Uhr schrieb James Chapman <
[email protected]>:

Hi, There is a PR here to add appearing and disappearing methods #6527
https://github.com/xamarin/Xamarin.Forms/pull/6527


You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/xamarin/Xamarin.Forms/issues/6486?email_source=notifications&email_token=AIC5IZ4I2JZNPBUEVTAGVKDP2VUTNA5CNFSM4HW2SLUKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODXZBIXY#issuecomment-502404191,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AIC5IZ776ASHDBUIXXNFHW3P2VUTNANCNFSM4HW2SLUA
.

I get this annoying behavior on the first appearance of the Shell.
I wanted to intercept the display and push a modal in certain conditions, but Appearing is not fired (and OnNavigated is fired twice)

@JeanCollas

(and OnNavigated is fired twice)

Can you expand on this? what values is it fired with? do you load the shell then navigate?

@PureWeen Actually I am writing about the ShellPage itself.
The OnAppearing method is not called at first show, but the OnNavigated is called twice (based on breakpoints stops).
I noticed because I have a breakpoint there, AND because I have a boolean telling me "First Start", which is therefore false on the second call.

Both calls have the same CallStack, I don't see any difference between the calls:

AppShell.OnNavigated
External Code
AppShell.InitializeComponent
AppShell..ctor
App..ctor
MainActivity.OnCreate

This is tested on an Android emulator.

BTW I tried the following in App.Xaml.cs to overcome both issues, but it did not change a thing:

            var appShell = new AppShell();
            MainPage = new TempPage();
            MainPage = appShell;

same issue in 4.1,4.2,4.3 also. please resolve it asap.

@JeanCollas your scenario should be fixed

@eramrit78

What's your use case for needing OnAppearing at the Shell level?
I just want to make sure we're matching up with your scenario

` public partial class AppShell : Xamarin.Forms.Shell
{
public AppShell()
{
InitializeComponent();
PrepareShell();

    }

    private void PrepareShell()
    {
        FlyoutItem tb = new FlyoutItem();
        Tab tab1 = new Tab { Icon = "live", Title = "Live", Style = (Style)Resources["BaseStyle"] };
        tab1.Items.Add(new ShellContent { Content = new LiveVideo() });

        Tab tab2 = new Tab { Icon = "shows", Title = "Reality Shows", Style = (Style)Resources["BaseStyle"] };
        tab2.Items.Add(new ShellContent { Content = new VideoList("RS") });

        Tab tab3 = new Tab { Icon = "news", Title = "Daily Lesson", Style = (Style)Resources["BaseStyle"] };
        tab3.Items.Add(new ShellContent { Content = new VideoList("News") });

        Tab tab4 = new Tab { Icon = "events", Title = "Daily Lesson", Style = (Style)Resources["BaseStyle"] };
        tab4.Items.Add(new ShellContent { Content = new VideoList("Events") });
        tb.Items.Add(tab1);
        tb.Items.Add(tab2);
        tb.Items.Add(tab3);
        tb.Items.Add(tab4);
        this.Items.Add(tb);
    }
}`

My scenario is that the above code under prepareshell should be call on appearing. because some page give an issue on re-route or 2nd call. so that there should be a option for recreate the instance of page under appshell.

Thanks

Hi
No solution found of my issue so that i have remove shell from my app. now it work fine.

dear team kindly understand the shell feature is lot of bugs and limits. we cannot start a app using shell with these bugs. It should me more flexible for developer.

Thanks

@eramrit78

1) why don't you declare all of that inside XAML?
2) What you have above should just work from code OnAppearing isn't going to change whether that works or doesn't work. Can you log an issue with a repro so we can look at fixing your issues?

The thing about OnAppearing on the Shell is that it's kind of a meaningless call. OnAppearing just indicates that something as the intent to Appear so once this is implemented it'll most likely be very close if not identical to just putting code into your constructor.

Anything that involves putting together the structure of the Shell should be finished well before any platform code starts to initialize

Hi

I agree OnAppearing is meaningless in shell. there should be a option reinstance of page which calls using shellcontent. like init shell.

Thanks

Hi

Look at my scenario. it clear you the onAppearing need.Look at screen shots first time in bottom tab show login button. after login it load the dashboard but in bottom tab it still show login button. there should be a dashboard button which show after login.But it show after close and re open the app. this is a one example where we need OnAppearance Event in AppShell.

Screenshot_1569675890
Screenshot_1569675942

@PureWeen , when I try to navigate using GoToAsync, the OnNavigated event isn't fired. Dig into the code I see this occur because of sectionController.PresentedPage?.SendAppearing();in the actual implementation of ShellSection.PresentedAppearing(), don't trigger the BaseShellItem.SendAppearing() and the _hasAppearing always is false and because of that the BaseShellItem.OnAppearing() never execute the Action.

So this bug indicates it was fixed as follows: Fixed by #6527
I look at that item and I cannot seem to tell its state. Has this fix been released to production? What release is it slated for release etc.

@gceaser I tested with the #6527 code.

The thing about OnAppearing on the Shell is that it's kind of a meaningless call. OnAppearing just indicates that something as the intent to Appear so once this is implemented it'll most likely be very close if not identical to just putting code into your constructor.

@PureWeen if it's meaningless then it shouldn't be there in the first place, what's the point of allowing me to override it if you're not going to execute the overriding code.

if it's an excess baggage from the base Page class i believe it can be hidden, however I think there might be some good use case for the OnAppearing

@Darlingtone I agree and think it would make a lot of sense to have the onappearing event, not everybody is using shell only.

@PureWeen When we set the xamarin.forms shell as main page after we logged in, the shell appears, then we want to be able to show modal dialogs, which is currently not possible because the onappearing event is not firing.

We do not want to put everything in the shell.xaml currently because there are a few known bugs, which keeps us from doing it.

Is it going to be fixed or is there any work around to get notified as soon as the shell appears?

@Darlingtone Also the actual Shell object is not instantiated until after the constructor completes. In my scenario, I want to be able to analyze the configuration state of my app and navigate to various shell menu options depending on what is complete / incomplete. Additionally, the constructor is not asynchronous. Thus a line of code such as this:

await Shell.Current.GoToAsync("//NetworkConfiguration", pb_Animated);

would would not compile if placed in the Constructor. Taking the Await will cause a runtime exception as the Shell object has not been created before the constructor runs. Thus, the need to on appearing.

@larsduewel

When we set the xamarin.forms shell as main page after we logged in, the shell appears, then we want to be able to show modal dialogs, which is currently not possible because the onappearing event is not firing.

So it sounds like you need OnAppeared not OnAppearing? Most likely when we get OnAppearing to fire it'll be right before the shell renderer is created so it won't actually be visible yet to the user.

What we really need in forms is a "Loaded" or something indicating it's been added to the visual tree :-/

@gceaser

I want to be able to analyze the configuration state of my app and navigate to various shell menu options depending on what is complete / incomplete. Additionally, the constructor is not asynchronous. Thus a line of code such as this:

Apps can't reliably wait async behavior before it loads though as this will effect load time. On iOS you have to present the main page after a certain amount of time otherwise it'll just shut down the app. If you need to perform an async operation before knowing the destination then you'd moist likely want to start on a "loading..." page and then navigate from there

@PureWeen the logic is about 10 lines of code long. The on appearing of the Shell is the PERFECT place to put it having to create a whole new "Loading" page and handle all the items surrounding that.

In my opinion:
1) If the Shell is a type of Page - as all the documentation indicates it is, it should implement all the corresponding events of a page.
2) If the developers of shell don't want to implement ALL the behaviors of the, they should look for a different type to use as the base.

I.E. Fix it or change its type.

Here is the intellisense for the Shell Class:

image

@gceaser but if you put async logic into OnAppearing it's going to be an async void class and you can't reliably make decisions here on how you want shell to be structured

The initial page that gets shown in an app should be a fast synchronous process. You can work to make it async but it will most likely be unreliable and quirky because either

1) you have to block the UI Thread so nothing loads
2) you have to not block the UI Thread. In which case Shell is going to load despite you and if you change the Shell structure it'll be basically the same as just having a loading screen for the user.

I agree with your opinions but the main purpose of my conversation here is to understand what people are trying to achieve. Because I have a strong feeling I'm going to implement OnAppearing then get a bunch of bugs about "I still can't do this thing with OnAppearing"

Making async decisions about what your initial page should be inside OnAppearing is an unreliable mechanism

If we want to implement this type of behavior then we should make it part of Shell. We should add a view that could act as the "Needs to load something template"

Then when that thing is done you could tell shell you are ready for the app and then the accurate shell could load in

@PureWeen

but if you put async logic into OnAppearing it's going to be an async void class and you can't reliably make decisions here on how you want shell to be structured

I am not structuring the Shell in the OnAppearing. I am simply verifying what app data is present and making automated navigation choises based on the presense of said data. Sorry for any confusion. All I am doing is calling a method with await from inside the Async OnAppearing to determine where to navigate to. I am interested in knowing how this is not reliable (since this is where and how we have been told to load data for a page in our app for years).
protected async override void OnAppearing()
{
try
{
base.OnAppearing();
await NavHelper.NavigateToRoute();
}
catch (Exception ex)
{
App.ProcessException(ex);
}
}

    public async static Task **NavigateToRoute**(bool pb_Animated = true)
    {
        try
        {
            if (ViewModelObjects.AppSettings.ServerIPAddress.ToString() == "0.0.0.0" ||
                ViewModelObjects.AppSettings.ServerPort == 0)
            {
                await Shell.Current.GoToAsync("//NetworkConfiguration", pb_Animated);
            }
            else if (ViewModelObjects.AppSettings.ClientFormFields.Count == 0)
            {
                await Shell.Current.GoToAsync("//FormConfiguration", pb_Animated);
            }
            else
            {
                await Shell.Current.GoToAsync("//Home", pb_Animated);
            }    
        }
        catch (Exception ex)
        {
            App.ProcessException(ex);
        }
    }

The initial page that gets shown in an app should be a synchronous process. You can work to make it async but it will most likely be unreliable and quirky because either.....

Again see the example above. 1) I am not blocking the UI thread -- and 2) the shell has already loaded and I am not changing it (the page actually loads between the constructor and the OnAppearing as far as I understand) so we have access to the any of the shell objects in order to customize it or perform navigation.

Making async decisions about what your initial page should be inside OnAppearing is an unreliable mechanism
I believe this is an opinion, which I obviously disagree with. Once the page is loaded -- Even a "Loading" type page - in order to do something like ensure the "is busy" indicator of the page correctly displays say while loading data - you need to call an async method with the await. - then when you are done making the async call (say maybe to load data for example), the is busy can be turned off. In fact I have read in several places that using async on the OnAppearing event is the correct place to way to call your methods to load your app data into observable collections etc. Has this changed? If not then I am a little confused in how this is different.

Let's please stop talking about

All I am doing is calling a method with await from inside the Async OnAppearing to determine where to navigate to. I am interested in knowing how this is not reliable (since this is where and how we have been told to load data for a page in our app for years).

Loading data in onappearing is fine

If you're loading your data then you're on a physical page so navigation has been solidified. At this point you have a page loaded where you can have a label Your data is loading please hold

Navigating based on the results of an async operation in OnAppearing I'd say is not fine

If you navigate from OnAppearing based on async results then Shell is going to just load whatever ShellItem you have specified first. Once your data loads it will then navigate a second time. If that initial ShellItem it loads is a "Loading Screen" and then inside that Loading Screens OnAppearing you do the async decision then that's basically the same thing as doing it from Shell.OnAppearing

What I'm seeing in your sample

Looking at your specific sample I would say that my plans for OnAppearing will fulfill your needs 👍 because you're just wanting to modify the active shell item based on a synchronous check. This is basically the scenario I'm targeting for OnAppearing with Shell. I'd like it fire right before the native renderer gets created so users have time to address any navigation or structure changes. That being said if you do anything like
```C#
await some operation
await GotoAsync


That will not perform how you want it to

Where as
```C#
await GotoAsync
await some operation

will

@gceaser I hate giving this kind of advice 👎

but I'm curious (for now) if the following code would work for you

```C#
public partial class ShellPage : Shell
{
public ShellPage()
{
InitializeComponent();

    Device.BeginInvokeOnMainThread(async () =>
    {
        await NavHelper.NavigateToRoute();
    });
 }

}
```

@PureWeen no this does not work as the Shell object had not been instantiated yet. That is exactly what I have been talking about for the last several posts. A page object (i.e. the shell) is not instantiated until AFTER the constructor. This attempting anything that accesses the Shell object in the initializer generates a null object exception.

@PureWeen I was wrong. What you posted actually does work. Thank you - this is a least a work around for now.

@gceaser Yay!!

Scenario validated 👍

@pictos do you have a repro

when I try to navigate using GoToAsync, the OnNavigated event isn't fired. Dig into the code I see this occur because of sectionController.PresentedPage?.SendAppearing();in the actual implementation of ShellSection.PresentedAppearing(), don't trigger the BaseShellItem.SendAppearing() and the _hasAppearing always is false and because of that the BaseShellItem.OnAppearing() never execute the Action.

I've tested a few different GoToAsync scenarios and for me OnNavigated is always firing

Is this bug going to be fixed? Because if shell inherits from Page but does not implement OnAppearing and also lets the user override it without it being called. Its really strange behavior and therefor Shell should not inherit from Page?

Especially if you use 3rd party frameworks that relay on OnAppearing to call WhenActivated/WhenDeactivted for example (ReactiveUI). Took us some time to figure out that OnAppearing is not being called.

So when it will be resolved?

<Shell xmlns="http://xamarin.com/schemas/2014/forms"
       xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
       Appearing="Shell_Appearing">
private void Shell_Appearing(object sender, System.EventArgs e)  {  }

Still Shell_Appearing() not triggered with 5.0.0-pre2.

Was this page helpful?
0 / 5 - 0 ratings