During a login flow, the login page does not normally have bottom tabs which constitute the main flow of the app.
AppShell.xaml
<TabBar>
<ShellContent Title="Home"
Icon="home.png"
ContentTemplate="{DataTemplate local:HomePage}"/>
<ShellContent Title="Articles"
Icon="articles.png"
ContentTemplate="{DataTemplate local:ArticlesPage}" />
</TabBar>
So I am attempting to navigate from the login page, given login successful, to the HomePage which is part of a TabBar in Shell. Problem is Shell then navigates to the HomePage as if it is a page on its own, without the TabBar.
I am assuming that the answer lies in navigating to the TabBar section itself, I don't know.
There are two ways to achieve your requirement.
Include LoginPage into AppShell
Set AppShell as MainPage in App.
Place Two Tabbar in AppShell , and place LoginPage first then HomePage, and set different Route for the two Tabbar.
<TabBar Route="Login">
<ShellContent ContentTemplate="{DataTemplate local:LoginPage}" />
</TabBar>
<TabBar Route="Home">
<ShellContent Title="Home" Icon="home.png" ContentTemplate="{DataTemplate local:HomePage}"/>
<ShellContent Title="Articles" Icon="articles.png" ContentTemplate="{DataTemplate local:ArticlesPage}" />
</TabBar>
Call await Shell.Current.GoToAsync("//Home"); when login in , Call await Shell.Current.GoToAsync("//Login"); when login out .
Don't Include LoginPage into AppShell
Set LoginPage as MainPage in App at first.
Call MainPage = new AppShell(); When login in , Call MainPage = new LoginPage(); when login out .
In addition to ColeX's answer, it will still work perfectly without the TabBar control.
<ShellContent ContentTemplate="{DataTemplate pages:LoginPage}"
Route="LoginPage"/>
<TabBar Route="Home">
<ShellContent Title="Home" Route="HomePage" Icon="home.png" ContentTemplate="{DataTemplate local:HomePage}"/>
<ShellContent Title="Articles" Route="ArticlesPage" Icon="articles.png" ContentTemplate="{DataTemplate local:ArticlesPage}"/>
</TabBar>
Login Button event-handler in LoginPage.xaml.cs
private async void BtnLogin_Clicked(object sender, EventArgs e)
{
// ApiHelper is a static class with methods that communicate with an API.
var response = await ApiHelper.Login(EntEmail.Text, EntPassword.Text);
if (response)
{
await Shell.Current.GoToAsync("//HomePage");
}
else
{
await DisplayAlert("", "Operation failed", "Cancel");
}
}
NOTE: EntEmail and EntPassword are the names of two Entry controls in LoginPage.xaml.
Related
In .NET MAUI, how do I use the OnPlatform element to conditionally include a ShellContent item in a FlyoutItem Items collection?
This Xaml will not compile (namespaces removed for clarity)
<Shell>
<FlyoutItem>
<OnPlatform x:TypeArguments="Items">
<On Platform="iOS">
<ShellContent
Title="Map"
ContentTemplate="{DataTemplate pages:MapPage}"
Route="MapPage" />
</On>
<On Platform="Android">
<ShellContent
Title="Map"
ContentTemplate="{DataTemplate pages:AMapPage}"
Route="MapPage" />
</On>
</OnPlatform>
There is a property IsVisible for ShellContent , you can use bind to achieve this.
Please refer to the following code:
AppShell.xaml.cs
public partial class AppShell : Shell
{
public bool isVisible_Android { get; set; }
public bool isVisible_iOS { get; set; }
public AppShell()
{
InitializeComponent();
if (Microsoft.Maui.Devices.DeviceInfo.Platform == DevicePlatform.iOS )
{
isVisible_iOS = true;
}
else if (DeviceInfo.Platform == DevicePlatform.Android)
{
isVisible_Android = true;
}
BindingContext = this;
}
}
AppShell.xaml
<FlyoutItem Title="Home" >
<ShellContent Title="Map" Route="MapPage" ContentTemplate="{DataTemplate local:MapPage}" IsVisible="{Binding isVisible_iOS}" />
<ShellContent Title="Map" Route="AMapPage" ContentTemplate="{DataTemplate local:AMapPage}" IsVisible="{Binding isVisible_Android}"/>
</FlyoutItem>
I've got an app that I am porting over to Maui from XF. I have a toolbaritem in my navigationbar. Here is the basic definition:
<ContentPage.ToolbarItems>
<ToolbarItem Text="New Game" Clicked="NewGame_Clicked" x:Name="NewGame" />
</ContentPage.ToolbarItems>
<VerticalStackLayout><ListView........./></VerticalStackLayout>
Here is my NewGame_Clicked Event:
private void NewGame_Clicked(object sender, EventArgs e)
{
Navigation.PushAsync(new EventSetupPage());
}
Here is the content of the EventSetupPage() overly simplified:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ScanAndScoringMauiApp.Pages.EventSetupPage"
Title="EventSetupPage">
<VerticalStackLayout>
<Label
Text="Welcome to .NET MAUI!"
VerticalOptions="Center"
HorizontalOptions="Center" />
</VerticalStackLayout>
</ContentPage>
When the EventSetupPage() comes up, it is blank in an android 12 emulator. The constructor is called, so I know that something is happening. It's like the page is being loaded in the wrong thread. I'm doing something wrong. Any thoughts on what I should do to get my page to load? TIA
********** update 1 ************
As an fyi, I am loading the parent page via a messagecenter message. I do this in my xamarin forms app.
MessagingCenter.Subscribe<string>(this, "UpdateMainPage", (sender) =>
{
MainThread.BeginInvokeOnMainThread(() =>
{
MainPage = new NavigationPage(new GameList());
});
});
I'm developing a simple UI5 project be able to learn how Router works.. In that process I'm faced with an issue related to Router events. I've three XML view which names are FirstPage, SecondPage and ThirdPage. The ThirdPage is implemented inside the other two pages as following code;
<mvc:XMLView viewName="SapUI5Tutorial.Application.Main.views.ThirdPage.view.ThirdPage"/>
For example FirstPage.xml
<mvc:View displayBlock="true" controllerName="SapUI5Tutorial.Application.Main.views.FirstPage.controller.FirstPage"
xmlns:mvc="sap.ui.core.mvc"
xmlns:core="sap.ui.core"
xmlns:l="sap.ui.layout"
xmlns="sap.m" height="100%">
<Page title="First Page" class="sapUiNoContentPadding">
<subHeader>
<Toolbar>
<VBox width="100%" alignItems="Center">
<Button text="Second Page Link" press="handleNavSecondPage"/>
</VBox>
</Toolbar>
</subHeader>
<mvc:XMLView viewName="SapUI5Tutorial.Application.Main.views.ThirdPage.view.ThirdPage"/>
</Page>
When I click "Second Page Link" button I'm navigating to SecondPage. But the ThirdPage is due to inside of SecondPage ThirdPage's Router function is running twice
ThirdPage's controller;
sap.ui.define([
"sap/ui/core/mvc/Controller",
], function (Controller, FragmentController) {
"use strict";
var base, oRouter;
return Controller.extend("SapUI5Tutorial.Application.Main.views.ThirdPage", {
onInit: function () {
base = this;
base.getView().setModel(oModel);
oRouter = sap.ui.core.UIComponent.getRouterFor(base);
oRouter.getRoute("FirstPage").attachMatched(base.firstPagePatternMatched, base);
oRouter.getRoute("SecondPage").attachMatched(base.secondPagePatternMatched, base);
},
firstPagePatternMatched: function (oEvent) {
console.log(oEvent)
},
secondPagePatternMatched: function (oEvent) {
//Due to the third page is used for inside two other pages (FirstPage and SecondPage) this function is running twice
console.log(oEvent)
}
});
});
How can I prevent running twice that Router event of ThirdPage ? Thank you for your helps
Since you have the Thirdpage view inside of the first page, you need not have another patternMatched function for the ThirdPage.
Morover, I don't see a need of having a separate controller for the ThirdPageView. You can and should reuse the parent FirstView's controller.
I believe your issue is with using .attachMatched instead of .attachPatternMatched
The former fires for any route or subroute whereas the latter fires for only the subroute.
The documentation is not very clear on this but can be found here.
I've created an app with SAPUI5 that makes use of a Flexible Column Layout.
I'm trying to navigate between pages, but I'm having difficulty.
Here is the main xml view:
<mvc:View id="Main" controllerName="SAP.demo.controller.Main" xmlns:html="http://www.w3.org/1999/xhtml" xmlns:mvc="sap.ui.core.mvc"
displayBlock="true" xmlns="sap.f" xmlns:core="sap.ui.core" xmlns:m="sap.m">
<m:App id="idAppControl">
<m:pages>
<m:Page title="{i18n>title}">
<m:content>
<FlexibleColumnLayout id="fcl" initialMidColumnPage="start" layout="TwoColumnsBeginExpanded">
<beginColumnPages>
<m:Page title = "Master">
<m:content>
<Button text="Chart Button" press="displayChart"/>
</m:content>
</m:Page>
</beginColumnPages>
<midColumnPages>
<m:Page id="start" title = "Detail">
<m:content>
<core:Fragment fragmentName="SAP.demo.view.Start" type="XML"/>
</m:content>
</m:Page>
<m:Page id="charts" title="Charts">
<m:content>
<core:Fragment fragmentName="SAP.demo.view.Charts" type="XML"/>
</m:content>
</m:Page>
</midColumnPages>
</FlexibleColumnLayout>
</m:content>
</m:Page>
</m:pages>
</m:App>
I want to navigate from the start page to the charts page. The controller is as follows:
sap.ui.define([
"sap/ui/core/mvc/Controller"], function (Controller) {
"use strict";
return Controller.extend("SAP.demo.controller.Main", {
displayChart:function(oEvent){
this.byId("fcl").toMidColumnPage("charts");
}
});});
Can someone please advise as to what I'm doing wrong, because it stays on the start page even after I press the button.
This is because the real ID of the view is not "charts" but "__xmlview0--charts".
Be careful with the ID always and use the API method byId('theIDHere').
In your case use one of the following options:
displayChart:function(oEvent){
this.getView().byId("fcl").toMidColumnPage(this.getView().byId("charts"));
}
Or
displayChart:function(oEvent){
this.getView().byId("fcl").toMidColumnPage(this.getView().byId("charts").getId());
}
And also add the correct XML namespace to your button
<m:Button text="Chart Button" press="displayChart"/>
Managed to fix it with the following code:
displayChart: function () {
this.byId("fcl").toMidColumnPage(this.createId("charts"));
},
I'm new at GWT and I wonder myself how to use an Activity, Place ,EventBus and UIbinder.
The layout of my app is smth like this :
Widget 1:
<g:DockLayoutPanel ui:field="myPanel" unit='PX'>
<g:north size='60'>
<m:HeaderPanelImpl styleName='{res.style.panelBorder}' ui:field='headerPanel' />
</g:north>
<g:south size='60'>
<g:HTMLPanel styleName='{res.style.panelBorder}' ui:field='footerPanel' />
</g:south>
<g:center>
<g:SimpleLayoutPanel styleName='{res.style.panelBorder}' ui:field='centerPanel' />
</g:center>
</g:DockLayoutPanel>
Here in "widget1.headerPanel" a have navigation which controls which widget to be shown in “widget1.centerPanel”.
The widgets which have to be shown in “widget1.centerPanel” are “widget2.0” and ”widget2.1”.
Widget2.0
<g:DockLayoutPanel unit='PX'>
<g:north size='100'>
<g:HTMLPanel styleName='{res.style.panelBorder}'>
<g:Label>TopPanel</g:Label>
</g:HTMLPanel>
</g:north>
<g:west size='200'>
<g:HTMLPanel styleName='{res.style.panelBorder}'>
<g:Label>LeftPanel</g:Label>
</g:HTMLPanel>
</g:west>
<g:east size='200'>
<g:HTMLPanel styleName='{res.style.panelBorder}'>
<g:Label>RightPanel</g:Label>
</g:HTMLPanel>
</g:east>
<g:center>
<g:SimpleLayoutPanel styleName='{res.style.panelBorder}' ui:field='centerPanel' />
</g:center>
</g:DockLayoutPanel>
Widget2.1
<g:HTMLPanel>
<g:Label>Settings</g:Label>
</g:HTMLPanel>
In ”widget2.0.topPanel” I have navigation which controls which widget will be shown in “widget2.0.centerPanel”
The widgets which have to be shown in “widget2.centerPanel” are “widget3.0” and ”widget3.1”.
Widget3.0
<g:HTMLPanel>
<g:Label>Content 1</g:Label>
</g:HTMLPanel>
Widget3.1
<g:HTMLPanel>
<g:Label>Content 2</g:Label>
</g:HTMLPanel>
My question is how to handle "onPlaceChangeEvent" ?
In example if url is mydomain.com/myapp.html#home:content1
the app has to show widget 1, widget 2.0 and widget 3.0
If the url is mydomain.com/myapp.html#home:content2
the app has to show widget1, widget 2.0 and widget 3.1
If the url is mydomain.com/myapp.html#settings
the app has to show widget1 and widget 2.1
I'm wondering between two variants :
To create to 2 ActivityManagers. One for the activities from widget1.navigation and one for the activites from widget2.navigation. But what happens if widget2 is created before widget 1 ?
To create one Activity which creates couple views.
Code:example
public class MonthlyViewActivity extends AbstractActivity implements MonthlyView.Presenter {
private Widget2_0 widget2_0;
private Widget3_0 widget3_0;
......
public void start(AcceptsOneWidget panel, EventBus eventBus) {
widget2_0 = new Widget2_0();
widget3_0 = new Widget3_0();
..........
}
....
}
What is the best practice for this case ?
if you are using eclipse create a MVP architecture in your project it will create many files like activity, place, one interface, one implementation class and a corresponding ui xml class. you have to create a activity mapper and activity history manager class. and in your on lode module set a default place for your application. after words on any event call go to method for any place and provide the link of your page and there check the get the value of token amd on basis of that value display your widgets what you want to display.