Xamarin Forms Master Detail Keep Master on the left - c#

I am trying to keep the Master page (menu) to the left of My MasterDetailPage at all times, I do not want the navigation to take the user away from the MasterDetailPage and make the user press a back button to get back.
I am looking a traditional burger bar menu to the left that simply changes the Detail page and keeps the master in place.
What I have now:
public partial class App : Application
{
public static NavigationPage NavPage { get; private set; }
private static RootPage RootPage;
public static bool MenuIsPresented
{
get
{
return RootPage.IsPresented;
}
set
{
RootPage.IsPresented = value;
}
}
public App()
{
InitializeComponent();
MenuPage menuPage = new MenuPage();
NavPage = new NavigationPage(new FirstPage());
RootPage = new RootPage();
RootPage.Master = menuPage;
RootPage.Detail = NavPage;
MainPage = RootPage;
}
...
}
And my ViewModel Command
async void GoSecondPageAsync(object obj)
{
await App.NavPage.PushAsync(new SecondPage());
App.MenuIsPresented = false;
}
But this just creates a new page on top of the stack with a back button back to the MasterDetailPage, while all I want is to stay within the MasterDetailPage.

You can push the new page and just remove the first one from the NavigationStack For example:
async void GoSecondPageAsync(object obj)
{
await App.NavPage.PushAsync(new SecondPage());
var removePage = App.NavPage.Navigation.NavigationStack[0];
App.NavPage.Navigation.RemovePage(removePage);
App.MenuIsPresented = false;
}
Although, if you just always want to replace the page do you really even need the NavigationPage and can't you just set the RootPage.Detail=new SecondPage();

You just need to update the Detail property to point to the new page. Like this:
async void GoSecondPageAsync(object obj)
{
RootPage.Detail = new NavigationPage(new SecondPage());
App.MenuIsPresented = false;
}

Related

MasterDetailPage breaks when rendered as NavigationPage

I would like to create an application with a navigation drawer. So each page should be accessible via drawer "link" item.
To protect those pages the application should only be accessible on a valid session otherwise the login page should be rendered.
I'm trying to explain what I've done so far for reproduction purposes...
After creating a new Xamarin forms project I created a MainPage holding the drawer and the currently rendered page
public class MainPage : MasterDetailPage
{
public MainPage()
{
Master = new MasterPage();
Detail = new NavigationPage(new DummyPage()); // Set initial page
}
}
So the MasterPage (drawer) is empty for now
internal class MasterPage : ContentPage
{
public MasterPage()
{
Title = "Master";
Content = new StackLayout { Children = { } };
}
}
Same for the rendered DummyPage
class DummyPage : ContentPage
{
public DummyPage()
{
Title = "Dummy";
Content = new StackLayout { Children = { new Label { Text = "Dummy Page" } } };
}
}
So without a LoginPage my App file would look like
public partial class App : Application
{
public App()
{
InitializeComponent();
MainPage = new MainPage();
}
}
The rendered application then looks fine
When I try to render a LoginPage before accessing the main application part I would do something like
public partial class App : Application
{
public App()
{
InitializeComponent();
Page initialPage;
if (false) // check if logged in
{
initialPage = new LoginPage();
}
else
{
initialPage = new MainPage();
}
MainPage = new NavigationPage(initialPage);
}
}
Unfortunately the rendered MainPage then looks like
How can I fix that? What is missing or wrong?
Update
I found out that I can set the current displayed page globally. So for the start I do
public App()
{
InitializeComponent();
Page initialPage;
if (isLoggedIn)
{
initialPage = new LoginPage();
}
else
{
initialPage = new MainPage();
}
MainPage = initialPage;
}
and when clicking the "Sign In" button on the LoginPage I don't execute
SignInCommand = new Command(() =>
{
await Application.Current.MainPage.Navigation.PushAsync(new MainPage());
});
This works for me
SignInCommand = new Command(() =>
{
Application.Current.MainPage = new MainPage();
});
You should try this
public partial class App : Application
{
public App()
{
InitializeComponent();
MainPage = new MainPage(false);
}
}
public class MainPage : MasterDetailPage
{
public MainPage(bool value)
{
Master = new MasterPage();
Detail = value ? new NavigationPage(new LoginPage()) : new NavigationPage(new DummyPage());
}
}
I think navigation doesn't add the main container.
It seems that you put the MasterDetailPage in a NavigationPage . Actually , it is nappropriate to do it . You could improve the code like following
public partial class App : Application
{
public App()
{
InitializeComponent();
if (false) // check if logged in
{
MainPage = new NavigationPage(initialPage);
}
else
{
MainPage = new MainPage();
}
}
}

Getting a empty list inside a button click Xamarin.Forms

I am new to Xamarin and MVVM. In my application I have Tabbed page and I have two child views inside. I am making a network call and getting data from databse in my first child's view model. Data is coming. I wanted to pass some data to my second child(List). I was able to pass data correctly. Inside my second child, I have a button and calling a new Page.
First child's ViewModel...
public async Task getFypDataAsync(string accessToken)
{
fypFullList = await _apiServices.GetFypData(accessToken);
fypFullList.Sort((x, y) => x.rank.CompareTo(y.rank));
fypSendList.AddRange(new List<FypRankData>(fypFullList.GetRange(0, 320)));
new HomeTab2(fypSendList); // send data to second child
}
List's data is available inside my second child's constructor (code behind).
Second child's code behind....
public partial class HomeTab2 : ContentPage
{
bool _istapped = false;
public List<FypRankData> mylist = new List<FypRankData>();
public HomeTab2()
{
InitializeComponent();
BindingContext = new HomeTabVM2();
var vm = BindingContext as HomeTabVM2;
vm.setFypData();
}
public HomeTab2(List<FypRankData> fypSendList)
{
mylist = fypSendList;
Debug.WriteLine(fypSendList.Count.ToString(), " list_yyycount ");
}
private async void Btn1_Clicked(object sender, EventArgs e)
{
if (_istapped)
return;
_istapped = true;
await Navigation.PushAsync(new ChartPage(mylist));
_istapped = false;
}
}
Problem is inside the button click mylist is getting empty. But inside the constructor, value is assigning.

PushAsync is not supported globally on Android, please use a NavigationPage

I'm doing a Master Detail Page as a menu and I'm getting this error:
PushAsync is not supported globally on Android, please use a NavigationPage.
When I try to instantiate another page. I believe my code already creates a navigation page when instantiate the page, but I'm not sure. Can someone help me?
App.xaml.cs:
public partial class App : Application
{
static public MasterDetailPage MasterDetail { get; set; }
public async static Task NavigateMasterDetail(Page page)
{
App.MasterDetail.IsPresented = false;
await App.MasterDetail.Navigation.PushAsync(page);
}
public App ()
{
InitializeComponent();
MainPage = new selectPage();
}
Page that carry the menu, selectPage:
public partial class selectPage : MasterDetailPage
{
public selectPage()
{
InitializeComponent();
this.Master = new Master();
this.Detail = new NavigationPage(new Detail());
App.MasterDetail = this;
}
}
Master.xaml.cs:
public Master ()
{
InitializeComponent ();
toDivPage.Clicked += async (sender, e) =>
{
await App.NavigateMasterDetail(new MainPage());
};
toBiqPage.Clicked += async (sender, e) =>
{
await App.NavigateMasterDetail(new MainPage());
};
}
Detail.xaml.cs is empty.
I believe you have to use NavigationPage in your App.xaml.cs.
In your App.xaml.cs make sure your constructor or App method looks like this
public App ()
{
InitializeComponent();
MainPage = new NavigationPage(new selectPage());
}
I hope this helps

how to pass ObservableCollection from one page1 to page2 without use MVVM

I want to pass ObversableCollecion temp from page1 to page2 ,when I click the button in page1.But I don't wan't to use MVVM,just be simnple.My code are as follows:
page1:
public ObservableCollection<Staff> Staff_Collection { get; set; }
private void button_click1(object sender, RoutedEventArgs e)
{
Page1 page1= new Page1();
page1.Staff_Show = Staff_Collection;
this.NavigationService.Navigate(page1);}
page2:
public ObservableCollection<Staff> Staff_Show = new ObservableCollection<Staff>();
public TaxBefore_Sum()
{
InitializeComponent();
DataContext = this;
Staff_Show = new ObservableCollection<Staff>();
}
but it doesn't work.
var whateverPage = new WhateverPage(whateverDataYouWantToPass);
this.NavigationService.Navigate(whateverPage);
Just make sure, the constructor for WhateverPage (the page you are navigating to) is overloaded to accept the item you are passing into it like this:
public WhateverPage(WhateverData data)
{
// code here
}
So in your case, if you are navigating to a page called Page2, then you will create a constructor in that page like this:
public Page2(ObservableCollection<Staff> staff)
{
// Now you have staff in Page2. You can assign it to a property or field
}

OnAppearing in children of TabbedPage is triggered only once

I have a TabbedPage in Xamarin.Forms:
public partial class MainPage : TabbedPage
{
public MainPage()
{
InitializeComponent();
var playPage = new NavigationPage(new PlayPage())
{
Title = "Play",
Icon = "play1.png"
};
var settingsPage = new NavigationPage(new SettingsPage())
{
Title = "Settings",
Icon = "settings.png"
};
var aboutPage = new NavigationPage(new AboutPage())
{
Title = "About",
Icon = "about.png"
};
Children.Add(playPage);
Children.Add(settingsPage);
Children.Add(aboutPage);
}
Each of the child pages are a ContentPage that overrides the OnAppearing method. The content of my child pages are not updating properly when I navigate between the tabs and further debugging tells me that the OnAppearing method for child pages are only called once (when the MainPage is first loaded).
Anyone have any idea why the OnAppearing method is only called once? And how can I solve this issue?
More Info
My child pages such SettingsPage contains events that when fired open another ContentPage using Navigation.PushAsync method. I expected the OnAppearing method to also get called when switching from tab pages and the navigation pages within those tab pages. (Hope this makes sense)
It only triggers once since the View is not destroyed when you navigate between tabs.
You can use the CurrentPageChanged event to figure our that a page has changed and signal the view it changes to and do whatever update of the view you need.
this.CurrentPageChanged += PageChanged;
void PageChanged(object sender, EventArgs args)
{
var currentPage = CurrentPage as MyTabPage;
currentPage?.UpdateView();
}
Then in your page:
public void UpdateView()
{
// do whatever you need here to update the page
}
Do not embedded your ContentPages within a "single" level NavigationPage.
The following works fine in terms of the OnAppearing event firing when switching between tabs:
public class PlayPage : ContentPage
{
protected override void OnAppearing()
{
System.Diagnostics.Debug.WriteLine("PlayPage");
base.OnAppearing();
}
}
public class AboutPage : ContentPage
{
protected override void OnAppearing()
{
System.Diagnostics.Debug.WriteLine("AboutPage");
base.OnAppearing();
}
}
public class SettingsPage : ContentPage
{
protected override void OnAppearing()
{
System.Diagnostics.Debug.WriteLine("SettingPage");
base.OnAppearing();
}
}
public partial class MainPage : TabbedPage
{
public MainPage()
{
var playPage = new PlayPage() { Title = "Play" };
var settingsPage = new SettingsPage() { Title = "Settings" };
var aboutPage = new AboutPage() { Title = "About" };
Children.Add(playPage);
Children.Add(settingsPage);
Children.Add(aboutPage);
}
}
public class App : Application
{
public App()
{
this.MainPage = new MainPage();
}
}

Categories