Speeding up Navigation

TrixoTrixo Member ✭✭

Hi, I have a little problem with my application.
It takes ages to navigate between pages.
My UIs are quite complex and some of the views have 1300lines of xaml code.
It takes around 4-5 seconds to change from one view to another. The xaml compilation is enebled.

public class Navigation
{

    // MAIN NAVIGATION, YOU CAN DEFINE MORE NAVIGATION TABS IN CONSTRUCTOR

    // List of navigation tabs
    public ObservableCollection<NavigationItem> NavigationItems { get; set; }
    Main MainPage { get; set; }
    Trends TrendsPage { get; set; }
    Settings SettingsPage { get; set; }
    //HOT_App.Views.Settings SettingsWindow;


    public Navigation()
    {
        NavigationItems = new ObservableCollection<NavigationItem>();

        NavigationItem Home = new NavigationItem("Home", "NavigationHome.png", true);
        NavigationItem Trends = new NavigationItem("Trends", "NavigationTrend.png", false);
        NavigationItem Settings = new NavigationItem("Settings", "SettingsIcon.png", false);


        NavigationItems.Add(Home);
        NavigationItems.Add(Trends);
        NavigationItems.Add(Settings);

    }


    public void ShowActiveNavigation()
    {
        System.Diagnostics.Debug.WriteLine(string.Join<NavigationItem>("\n", NavigationItems));
    }


    // navigation logic
    public async void SetActiveNavigation(string activeNavigationName)
    {
        NavigationItems[0].Active = false;
        NavigationItems[1].Active = false;
        NavigationItems[2].Active = false;
        //ChangeActiveValue(activeNavigationName);
        switch (activeNavigationName)
        {
            case "Home":
                NavigationItems[0].Active = true;
                //Application.Current.MainPage.Navigation.PopAsync(false);

                await Application.Current.MainPage.Navigation.PushAsync(new Main(), false);
                System.Diagnostics.Debug.WriteLine("Home");
                break;
            case "Trends":
                NavigationItems[1].Active = true;
                //Application.Current.MainPage.Navigation.PopAsync(false);
                await Application.Current.MainPage.Navigation.PushAsync(new MainPage(), false);
                System.Diagnostics.Debug.WriteLine("Trends");
                break;
            case "Settings":
                NavigationItems[2].Active = true;
                //Application.Current.MainPage.Navigation.PopAsync(false);
                await Application.Current.MainPage.Navigation.PushAsync(new HOT_App.Views.Settings(), false);
                System.Diagnostics.Debug.WriteLine("Settings");
                break;
            default:
                NavigationItems[0].Active = true;
                await Application.Current.MainPage.Navigation.PushAsync(new Main(), false);
                System.Diagnostics.Debug.WriteLine("Home");
                break;

        }

    }

    // updates active navigation tab
    public void ChangeActiveValue(string activeNavigationName)
    {
        foreach (NavigationItem navigationItem in NavigationItems)
        {

            if (navigationItem.NavigationItemName == activeNavigationName)
            {
                navigationItem.Active = true;
            }
            else { navigationItem.Active = false; }
        }
    }

}

Is there any way how to reuse the views instead of creating new ones? Like Instead of
Application.Current.MainPage.Navigation.PushAsync(new Main(), false);
I would write soemthing like but it doesnt work
Main Mainpage= new Main();
Application.Current.MainPage.Navigation.PushAsync(Mainpage, false);

Any ideas?

Best Answers

Answers

  • JarvanJarvan Member, Xamarin Team Xamurai

    Is there any way how to reuse the views instead of creating new ones?

    Try to set the page class to a singleton.

    sealed class Page1
    {
        private static Page1 _instance = null;
        private Page1()
        {
        }
        static internal Page1 Instance()
        {
            if (_instance == null)
            {
                _instance = new Page1();
            }
            return _instance;
        }
    }
    

    Tutorial about Implementing The Singleton Design Pattern.
    https://www.c-sharpcorner.com/article/implementing-the-singleton-design-pattern/

  • TrixoTrixo Member ✭✭
    edited September 24

    Jarvan the problem is that I get the exception "System.InvalidOperationException: Page must not already have a parent."

    Thats is the same problem as saving it to the variable.

    I tried //Application.Current.MainPage.Navigation.PopAsync(false); and hoped it would remove the parent but I didnt manage to do it.

  • TrixoTrixo Member ✭✭

    Thanks, I will check it out

  • JohnHardmanJohnHardman GBUniversity mod

    @Trixo said:
    Is there any way how to reuse the views instead of creating new ones? Like Instead of
    Application.Current.MainPage.Navigation.PushAsync(new Main(), false);
    I would write soemthing like but it doesnt work
    Main Mainpage= new Main();
    Application.Current.MainPage.Navigation.PushAsync(Mainpage, false);

    Using a much earlier XF version (it was probably 2.x), I implemented caching of ContentPages in my code. For the most part, it worked. However, I found odd pages where something completely unexpected would happen, typically in the laying out of the page content. I came to the conclusion that back then, caching of pages was too fragile and even more likely to break as a result of XF changes than pretty much anything else. As a result, I removed the page caching from my code.

    Seeing your question prompted me to do a little experimentation to see if things have improved (I am now using XF 4.x). I haven't encountered any of the strange layout issues, but as my experimentation this time has only been with really simple pages I am not surprised. However, there are enough complexities (e.g. with unexpectedly having to reset BindingContext properties) that I would be tempted to steer away from page caching unless there is nothing else to try.

    In your particular case, I would be tempted to simplify the XAML to only contain what is essential when the page first appears, lazy loading anything that is required later only when it is needed and not when the page first opens.

  • JohnHardmanJohnHardman GBUniversity mod

    @1xo2 said:
    I'm trying to create all children on background thread, then attach it to parent on UI thread

    If doing that, I suggest putting a wrapper around the code doing this so that you can easily switch it back to the UI thread if problems arise. Whilst it seems to work with XF 4.x, there were previously longstanding problems doing this on UWP if you did any work with fonts. Similarly, WebViews used to cause a problem doing this. Being able to easily change your code to put this work back on the UI thread, even if not ideal, at least allows you to continue working if a regression appears in XF itself.

    @1xo2 said:
    I'm trying to attach children only after page appear.

    Depending on how you do this, be aware that it can cause extra layout cycles. Lazy loading can be useful, but only do this in appropriate places.

    As per my earlier post, "I would be tempted to simplify the XAML to only contain what is essential when the page first appears, lazy loading anything that is required later only when it is needed and not when the page first opens."

    @1xo2 said:
    manage adequately your garbage collection.

    Before micro-managing garbage collection, I strongly recommend reading "Writing High-Performance .NET Code" by Ben Watson.

  • TrixoTrixo Member ✭✭

    Sorry guys I went for a holiday. I am finally back, I started with simplifying xaml code I will see at the end of the day if its faster or not

  • TrixoTrixo Member ✭✭

    I removed few bindings and optimized UI. I managed to speed up loading by 2 seconds and for now its fine, but I feel like xamarin is really limited in this way. Its very hard to create nice looking UI which loads fast. A lot of optimatization and workarounds is needed.

Sign In or Register to comment.