Showing ToolbarItem in Xamarin Forms with AppShell - xaml

In my Xamarin Forms 5 app, I'm trying to add a ToolbarItem to a ContentPage which is a "child" of a TabbedPage but the ToolbarItem is not showing.
The key point here is that the app uses AppShell and the tabs are defined in AppShell.xaml which looks like this:
<FlyoutItem Title="Home">
<FlyoutItem.Icon>
<FontImageSource
FontFamily="MISHRP"
Glyph="{StaticResource HomeIcon}"
Color="White" />
</FlyoutItem.Icon>
<ShellContent Route="HomePage" ContentTemplate="{DataTemplate local:HomePage}" />
</FlyoutItem>
And the home page has three tabs that point to ContentPage's:
<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
... // Removed for brevity>
<local:CommercialFeed Title="Feed" />
<local:PersonalCard Title="Card" />
<local:Vendors Title="Vendors" />
</TabbedPage>
I'm now adding a ToolbarItem in the "Vendors" page but it doesn't show. I read that I need to wrap main page in a NavigationPage.
I have two issues here:
Because I'm using AppShell, my code behind looks like this: MainPage = new AppShell();. So not sure how to handle this part. I tried MainPage = new NavigationPage(new AppShell()); but this created another issue -- see below -- and it also crashed the app.
I have a login page which is also defined in the AppShell. When I tried the above code, I got a nav bar on the login page as well and that's a problem. There shouldn't be a nav bar in the login page.
How do I handle this so that I can have ToolbarItems in my Vendors page? Thanks.

First, I believe it is a bad idea to mix Shell and the old TabbedPage (use either one of them), in my opinion it is better to change your ui structure from TabbedPage to a combination of Tabbar and Tab that both are within Shell Xamarin.Forms Shell tabs.
<TabBar>
<Tab Title="Feed">
<ShellContent Title="Feed" ContentTemplate="{DataTemplate local:CommercialFeed}"/>
</Tab>
<Tab Title="Cards">
<ShellContent Title="Cards" ContentTemplate="{DataTemplate PersonalCard}"/>
</Tab>
<Tab Title="Vendors">
<ShellContent Title="Vendors" ContentTemplate="{DataTemplate local:Vendors}"/>
</Tab>
</TabBar>
Now define ToolbarItems on each page:
<ContentPage.ToolbarItems>
<ToolbarItem Text="..." .../>
</ContentPage.ToolbarItems>
If you want to keep using TabbedPage anyway, check How to add toolbar item in TabbedPage in Xamarin Form

Related

How to set the flyout menu only on a certain page - .NET MAUI

The app I'm making is an app with recipes for meals. The first thing that is displayed to the user after starting the application is the Login page, where the user, after entering his data and clicking the 'LOGIN' button, goes to the home page. On that page there are some defined menus for dishes and what should be a menu, i.e. flyout menu in the upper left corner (as part of navbar) but there is no such thing. The only thing that is displayed is an arrow that takes you back to the Login page. I defined the flyout with elements (appetizer, main course and dessert) in the appshell, and tried to add properties so that the flyout is not visible on the Login page, but only after logging in. For the login page, I manage to make it with the help of the Shell.FlyoutBehavior="Disabled" property, but this same thing with the "Flyout" property for the home page does not work.
AppShell code:
<Shell
x:Class="ReceptiUI.AppShell"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:ReceptiUI"
Shell.FlyoutItemIsVisible="True"
Shell.FlyoutBehavior="Flyout">
<ShellContent
Shell.FlyoutBehavior="Disabled"
Title="Home"
ContentTemplate="{DataTemplate local:Login}"
Route="Login" />
<ShellContent
Shell.FlyoutBehavior="Flyout"
Title="Home"
ContentTemplate="{DataTemplate local:MainPage}"
Route="MainPage"/>
<FlyoutItem Title="Predjelo" Icon="breakfast.png">
<ShellContent ContentTemplate="{DataTemplate local:Breakfast}"/>
</FlyoutItem>
<FlyoutItem Title="Glavno jelo" Icon="food.png">
<ShellContent ContentTemplate="{DataTemplate local:Lunch}"/>
</FlyoutItem>
<FlyoutItem Title="Desert" Icon="dinner.png">
<ShellContent ContentTemplate="{DataTemplate local:Dinner}"/>
</FlyoutItem>
<FlyoutItem Title="Meni" Icon="dinner.png">
<ShellContent ContentTemplate="{DataTemplatelocal:ListaJela}"/>
</FlyoutItem>
I also set these properties
'Shell.FlyoutItemIsVisible="True"'
'Shell.FlyoutBehavior="Flyout"' on the home page, but still no flyout menu.
You can write a FlyoutPage in the home page instead of using the shell flyout in the AppShell.
Here is the code demo:
<FlyoutPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:FlyoutPageNavigation"
x:Class="FlyoutPageNavigation.MainPage">
<FlyoutPage.Flyout>
<local:FlyoutMenuPage x:Name="flyoutPage" />
</FlyoutPage.Flyout>
<FlyoutPage.Detail>
<NavigationPage>
<x:Arguments>
<local:ContactsPage />
</x:Arguments>
</NavigationPage>
</FlyoutPage.Detail>
</FlyoutPage>
In the AppShell, you just write a normal navigation to navigate from the Loginpage to the Homepage.

Add query parameter to a Xamarin Forms Shell route

(Posted this question on the Microsoft forum as well)
Similar to How do I add a route query parameter to a ShellContent item in a Xamarin Forms app , but this thread did not help me.
I've recently started a new project and decided to go with Xamarin Forms Shell.
I have a single content page that behaves differently based on the query parameter provided.
There is three tab items that will route to the same content page, each providing a different query parameter.
I can't figure out how to pass this parameter to my content page viewmodel via the AppShell.xaml route.
Please see my sample code below that replicates the requirement.
In ths sample I would like to set the content page label using the query parameter supplied in the xaml route.
Using the code below, I get a null reference exception.
AppShell.xaml:
<FlyoutItem Title="Sample">
<Tab Title="Red">
<ShellContent Route="SamplePage?Parameter=Red" ContentTemplate="{DataTemplate sample:SamplePage}" />
</Tab>
<Tab Title="Blue">
<ShellContent Route="SamplePage?Parameter=Blue" ContentTemplate="{DataTemplate sample:SamplePage}" />
</Tab>
<Tab Title="Green">
<ShellContent Route="SamplePage?Parameter=Green" ContentTemplate="{DataTemplate sample:SamplePage}" />
</Tab>
</FlyoutItem>
SamplePageVM:
[QueryProperty(nameof(Parameter), nameof(Parameter))]
public class SamplePageVM
{
public string Parameter { get; set; }
}
SamplePage.xaml:
<ContentPage.Content>
<Grid>
<Label Text="{Binding Parameter}"/>
</Grid>
</ContentPage.Content>
Any help would be appreciated.
Or alternative ways to approach this.
Thanks a lot.
*Edit
Below is my workaround for now.
AppShell.xaml:
<FlyoutItem Title="Sample">
<Tab Title="Red">
<ShellContent Route="RedRoute" ContentTemplate="{DataTemplate sample:SamplePage}" />
</Tab>
<Tab Title="Blue">
<ShellContent Route="BlueRoute" ContentTemplate="{DataTemplate sample:SamplePage}" />
</Tab>
<Tab Title="Green">
<ShellContent Route="GreenRoute" ContentTemplate="{DataTemplate sample:SamplePage}" />
</Tab>
</FlyoutItem>
AppShell.xaml.cs
protected override void OnNavigating(ShellNavigatingEventArgs args)
{
base.OnNavigating(args);
if (args.Target.Location.OriginalString.ToLower().Contains("redroute"))
{
StaticHelper.Parameter = "Red";
}
else if (args.Target.Location.OriginalString.ToLower().Contains("blueroute"))
{
StaticHelper.Parameter = "Blue";
}
else if (args.Target.Location.OriginalString.ToLower().Contains("greenroute"))
{
StaticHelper.Parameter = "Green";
}
}
SamplePageVM:
public class SamplePageVM
{
public string Parameter { get; set; }
public SamplePageVM()
{
Parameter = StaticHelper.Parameter;
}
}
SamplePage.xaml:
<ContentPage.Content>
<Grid>
<Label Text="{Binding Parameter}"/>
</Grid>
</ContentPage.Content>
Might not be best practice, but it's something.
I could be able to reproduce this exception. Check the screenshot: https://imgur.com/HNmjewa
System.NullReferenceException: 'Object reference not set to an instance of an object.'
Change the Route like below would fix this exception.
<FlyoutItem Title="Sample">
<Tab Title="Red">
<ShellContent ContentTemplate="{DataTemplate sample:SamplePage}" Route="Red" />
</Tab>
<Tab Title="Blue">
<ShellContent ContentTemplate="{DataTemplate sample:SamplePage}" Route="Blue" />
</Tab>
<Tab Title="Green">
<ShellContent ContentTemplate="{DataTemplate sample:SamplePage}" Route="Green" />
</Tab>
</FlyoutItem>
And if you want to use the query parameters, invoke the GoToAsync method with URI which includes all three components, the structure is: //route/page?queryParameters.
string monkeyName = (e.CurrentSelection.FirstOrDefault() as Animal).Name;
// The following route works because route names are unique in this application.
await Shell.Current.GoToAsync($"routename?Parameter={monkeyName}");
//routename is the string of the Route in xaml or register the code: Routing.RegisterRoute
For more details, you could download the code sample from the link below. https://learn.microsoft.com/en-us/samples/xamarin/xamarin-forms-samples/userinterface-xaminals/

Xamarin Form Shell: Flyout v/s TabBar

I'm confused by reading the sentence
TabBar disables the Flyout
in the Xamarin documentation. But even the sample code shows TabBar in Flyout layout. I guess, I misunderstood the Flyout and TabBar (my idea is as per attached). Anyone kindly visualize the difference. Google search didn't give much on the TabBar, it just shows the standard documentation.
It means if you use only Tabbar as a root element for your Shell, you will loose the Flyout, but if your root element is a FlyoutItem then you may benefit from both as in the picture you have shown.
From another side, you cannot explicitly nest a FlyoutItem inside of a Tabbar or the opposite.
When using a you can still define (Tabbar) bottom tabs but not explicitly:
<FlyoutItem FlyoutDisplayOptions="AsMultipleItems">
<ShellContent Title="First"
ContentTemplate="{DataTemplate local:Page1}"/>
<ShellContent Title="Seconde"
ContentTemplate="{DataTemplate local:Page2}"/>
</FlyoutItem>
In this example Page1 and Page2 will be displayed as bottom tabs AND as flyout items.
If for some reasons you want to display a page only as a bottom tab (hide it in the flyout), then you can set FlyoutItemIsVisible="False" on it ShellContent:
<FlyoutItem FlyoutDisplayOptions="AsMultipleItems">
<ShellContent Title="First"
ContentTemplate="{DataTemplate local:Page1}"/>
<ShellContent Title="Seconde" FlyoutItemIsVisible="False"
ContentTemplate="{DataTemplate local:Page2}"/>
</FlyoutItem>
EDIT
Example of bottom and top tabs with flyout generated without the explicit Tabbar element
<FlyoutItem FlyoutDisplayOptions="AsMultipleItems">
<Tab Title="1st Bottom Tab">
<ShellContent Title="1st Top tab"
ContentTemplate="{DataTemplate local:Page1}"/>
<ShellContent Title="Seconde" FlyoutItemIsVisible="False"
ContentTemplate="{DataTemplate local:Page2}"/>
</Tab>
<Tab Title="2nd Bottom Tab">
<ShellContent Title="First"
ContentTemplate="{DataTemplate local:Page1}"/>
<ShellContent Title="Seconde" FlyoutItemIsVisible="False"
ContentTemplate="{DataTemplate local:Page2}"/>
</Tab>
</FlyoutItem>
Conclusion
If you want a flyout (independently whether it is in addition to tabs wither top or bottom or both) go with a FlyoutItem as a root Element (no need for Tabbar).
if you don't want a flyout go with Tabbar as a root element.

TabbedPage tab icons not working with font awesome

I'm trying to add icons to my tabs with font awesome, in my Xamarin iOS/android app, I looked in many tutorials and I tried to do the same but something is wrong with the following code:
<TabbedPage.Children>
<mypages:List Title="Lista">
<Tab.Icon>
<FontImageSource FontFamily="{StaticResource FontAwesomeSolid}" Glyph="" Size="Small" />
</Tab.Icon>
</mypages:List>
</TabbedPage.Children>
Everything worked until I add the <Tab.Icon> Stuff.
The error you got is self-explanatory:
"The attachable property "Icon" was not found in type 'Tab' ", with <Tab.Icon> underlined.
There is no property called Icon in type Tab, you can use below but as you can see, it is IconImageSource which requires to provide a resource image name and not a font glyph.
<TabbedPage.Children>
<apptest:Page2 IconImageSource="imageName.png"/>
</TabbedPage.Children>
An alternative in order to use font icons would be to use Shell to build your tabs instead of TabbedPage, which provides font icon support thru FontImageSource:
<Shell>
...
<Tab Title="title">
<Tab.Icon>
<FontImageSource FontFamily="FontAwesome" Glyph="{x:Static fonts:IconFont.AddressBook}"/>
</Tab.Icon>
<ShellContent ContentTemplate="{DataTemplate local:Page1}"/>
</Tab>
Details about fontawesome in xamarin.forms: How to use Font Awesome icons in project as an icon of ImageButton

Is there a way to show Icon in Xamarin.Forms Shell top tab?

I'm trying to develop a UI using Xamarin.Forms (Shell Navigation). I have bottom tabs and in each bottom tab there are several top tabs. I can able to show bottom tab Icons but the top tab icons are not shown (invisible). However, the text is visible.
I already tried to set Icon="image.png" for top tabs as I did for bottom tabs. Still the icons on top tabs are not visible.
Part of my XAML code:
<TabBar>
<Tab Title="Browse" Icon="tab_feed.png">
<ShellContent ContentTemplate="{DataTemplate local:ItemsPage}" />
</Tab>
<Tab Title="About" Icon="tab_about.png">
<ShellContent ContentTemplate="{DataTemplate local:AboutPage}" />
</Tab>
<Tab Title="Test 2" Icon="tab_others.png">
<ShellContent Shell.NavBarIsVisible="False" Title="abt" Icon="tab_about.png" ContentTemplate="{DataTemplate local:AboutPage}" />
<ShellContent Title="fed" Icon="tab_feed.png" ContentTemplate="{DataTemplate local:ItemsPage}" />
</Tab>
</TabBar>
The Icons defined in ShellContent are not visible (titles are visible though).
Please provide any direction or document to attain this.