4

I'm trying to do a simple navigation between two frames using CommandBar. The documentation (https://platform.uno/docs/articles/controls/CommandBar.html) says the Native style is default, but on Android is not possible to see the BackButton and the bar doesn't look like Android.

Some settings:

App.xaml

<Application
    x:Class="UnoAppSimple.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:UnoAppSimple">
    
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />

                <!--Load Uno.UI.Toolkit resources-->  
                <ToolkitResources xmlns="using:Uno.Toolkit.UI" />

                
                <!--Load Material resources-->                  
                <MaterialColors xmlns="using:Uno.Material" />                
                <MaterialResources xmlns="using:Uno.Material" />

                
                <!--Load Cupertino resources-->                  
                <CupertinoColors xmlns="using:Uno.Cupertino" />                
                <CupertinoResources xmlns="using:Uno.Cupertino" />

                
                <!--Load Material Toolkit resources-->   
                <MaterialToolkitResources xmlns="using:Uno.Toolkit.UI.Material" />

                
                <!--Load Cupertino Toolkit resources-->  
                <CupertinoToolkitResources xmlns="using:Uno.Toolkit.UI.Cupertino" />
                
                <!-- Add resource dictionaries here -->
                
            </ResourceDictionary.MergedDictionaries>
            <!-- Add resources here -->
            
        </ResourceDictionary>
    </Application.Resources>

</Application>

App.xaml.cs

using Microsoft.Extensions.Logging;
using System;
using UnoAppSimple.Views;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Activation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;

namespace UnoAppSimple
{
    /// <summary>
    /// Provides application-specific behavior to supplement the default Application class.
    /// </summary>
    public sealed partial class App : Application
    {
        private Window _window;

        /// <summary>
        /// Initializes the singleton application object.  This is the first line of authored code
        /// executed, and as such is the logical equivalent of main() or WinMain().
        /// </summary>
        public App()
        {
            InitializeLogging();

            this.InitializeComponent();

#if HAS_UNO || NETFX_CORE
            this.Suspending += OnSuspending;
#endif
        }

        /// <summary>
        /// Invoked when the application is launched normally by the end user.  Other entry points
        /// will be used such as when the application is launched to open a specific file.
        /// </summary>
        /// <param name="args">Details about the launch request and process.</param>
        protected override void OnLaunched(LaunchActivatedEventArgs args)
        {
#if DEBUG
            if (System.Diagnostics.Debugger.IsAttached)
            {
                // this.DebugSettings.EnableFrameRateCounter = true;
            }
#endif

#if NET5_0 && WINDOWS
            _window = new Window();
            _window.Activate();
#else
            _window = Windows.UI.Xaml.Window.Current;
#endif

            var rootFrame = _window.Content as Frame;

            // Do not repeat app initialization when the Window already has content,
            // just ensure that the window is active
            if (rootFrame == null)
            {
                // Create a Frame to act as the navigation context and navigate to the first page
                rootFrame = new Frame();

                rootFrame.NavigationFailed += OnNavigationFailed;

                if (args.PreviousExecutionState == ApplicationExecutionState.Terminated)
                {
                    // TODO: Load state from previously suspended application
                }

                // Place the frame in the current Window
                _window.Content = rootFrame;
            }

#if !(NET5_0 && WINDOWS)
            if (args.PrelaunchActivated == false)
#endif
            {
                if (rootFrame.Content == null)
                {
                    // When the navigation stack isn't restored navigate to the first page,
                    // configuring the new page by passing required information as a navigation
                    // parameter
                    rootFrame.Navigate(typeof(PokemonsPage), args.Arguments);
                }
                // Ensure the current window is active
                _window.Activate();
            }

            ConfigureNavigation();
        }

        private void ConfigureNavigation()
        {
            var frame = (Frame)Windows.UI.Xaml.Window.Current.Content;
            var manager = Windows.UI.Core.SystemNavigationManager.GetForCurrentView();

#if WINDOWS_UWP || __WASM__
            // Toggle the visibility of back button based on if the frame can navigate back.
            // Setting it to visible has the follow effect on the platform:
            // - uwp: show a `<-` back button on the title bar
            // - wasm: add a dummy entry in the browser back stack
            frame.Navigated += (s, e) => manager.AppViewBackButtonVisibility = frame.CanGoBack
                ? Windows.UI.Core.AppViewBackButtonVisibility.Visible
                : Windows.UI.Core.AppViewBackButtonVisibility.Collapsed;
#endif

#if WINDOWS_UWP || __ANDROID__ || __WASM__
            // On some platforms, the back navigation request needs to be hooked up to the back navigation of the Frame.
            // These requests can come from:
            // - uwp: title bar back button
            // - droid: CommandBar back button, os back button/gesture
            // - wasm: browser back button
            manager.BackRequested += (s, e) =>
            {
                if (frame.CanGoBack)
                {
                    frame.GoBack();

                    e.Handled = true;
                }
            };
#endif
        }

        /// <summary>
        /// Invoked when Navigation to a certain page fails
        /// </summary>
        /// <param name="sender">The Frame which failed navigation</param>
        /// <param name="e">Details about the navigation failure</param>
        void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
        {
            throw new InvalidOperationException($"Failed to load {e.SourcePageType.FullName}: {e.Exception}");
        }

        /// <summary>
        /// Invoked when application execution is being suspended.  Application state is saved
        /// without knowing whether the application will be terminated or resumed with the contents
        /// of memory still intact.
        /// </summary>
        /// <param name="sender">The source of the suspend request.</param>
        /// <param name="e">Details about the suspend request.</param>
        private void OnSuspending(object sender, SuspendingEventArgs e)
        {
            var deferral = e.SuspendingOperation.GetDeferral();
            // TODO: Save application state and stop any background activity
            deferral.Complete();
        }

        /// <summary>
        /// Configures global Uno Platform logging
        /// </summary>
        private static void InitializeLogging()
        {
            var factory = LoggerFactory.Create(builder =>
            {
#if __WASM__
                builder.AddProvider(new global::Uno.Extensions.Logging.WebAssembly.WebAssemblyConsoleLoggerProvider());
#elif __IOS__
                builder.AddProvider(new global::Uno.Extensions.Logging.OSLogLoggerProvider());
#elif NETFX_CORE
                builder.AddDebug();
#else
                builder.AddConsole();
#endif

                // Exclude logs below this level
                builder.SetMinimumLevel(LogLevel.Information);

                // Default filters for Uno Platform namespaces
                builder.AddFilter("Uno", LogLevel.Warning);
                builder.AddFilter("Windows", LogLevel.Warning);
                builder.AddFilter("Microsoft", LogLevel.Warning);

                // Generic Xaml events
                // builder.AddFilter("Windows.UI.Xaml", LogLevel.Debug );
                // builder.AddFilter("Windows.UI.Xaml.VisualStateGroup", LogLevel.Debug );
                // builder.AddFilter("Windows.UI.Xaml.StateTriggerBase", LogLevel.Debug );
                // builder.AddFilter("Windows.UI.Xaml.UIElement", LogLevel.Debug );
                // builder.AddFilter("Windows.UI.Xaml.FrameworkElement", LogLevel.Trace );

                // Layouter specific messages
                // builder.AddFilter("Windows.UI.Xaml.Controls", LogLevel.Debug );
                // builder.AddFilter("Windows.UI.Xaml.Controls.Layouter", LogLevel.Debug );
                // builder.AddFilter("Windows.UI.Xaml.Controls.Panel", LogLevel.Debug );

                // builder.AddFilter("Windows.Storage", LogLevel.Debug );

                // Binding related messages
                // builder.AddFilter("Windows.UI.Xaml.Data", LogLevel.Debug );
                // builder.AddFilter("Windows.UI.Xaml.Data", LogLevel.Debug );

                // Binder memory references tracking
                // builder.AddFilter("Uno.UI.DataBinding.BinderReferenceHolder", LogLevel.Debug );

                // RemoteControl and HotReload related
                // builder.AddFilter("Uno.UI.RemoteControl", LogLevel.Information);

                // Debug JS interop
                // builder.AddFilter("Uno.Foundation.WebAssemblyRuntime", LogLevel.Debug );
            });

            global::Uno.Extensions.LogExtensionPoint.AmbientLoggerFactory = factory;

#if HAS_UNO
            global::Uno.UI.Adapter.Microsoft.Extensions.Logging.LoggingAdapter.Initialize();
#endif
        }
    }
}

PokemonsPage.xaml

<Page
    x:Class="UnoAppSimple.Views.PokemonsPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:UnoAppSimple.Views"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>

        <CommandBar Content="{Binding Title}" >
            
        </CommandBar>

        <StackPanel Grid.Row="1">
            <Button Content="Bulbasaur" Click="GoToPokemonDetailPageClicked"/>
        </StackPanel>
    </Grid>
</Page>
Sérgio Damasceno
  • 657
  • 1
  • 8
  • 18

1 Answers1

0

You'll need to force the use of the native iOS/Android styles for Frame in your application since the native style is no longer the default. You can do this by calling FeatureConfiguration.Styles.ConfigureNativeFrameNavigation() in your App.xaml.cs before the InitializeComponent().

Also, as an FYI, there is now a newer control that you can use for the native navigation bars. The NavigationBar control that lives inside of the Uno.Toolkit.UI packages is now the recommended control to use for this scenario. Installing the Toolkit package will automatically set the Frame default style to the native one for iOS and Android, no need for the FeatureConfiguration flag in this case. Docs for Toolkit can be found here: https://platform.uno/docs/articles/external/uno.toolkit.ui/doc/getting-started.html

sbilogan
  • 121
  • 4