How to push pages to MasterDetailPage using Mvvm - c#

I want to use Mvvm(Basic Mvvm) for MasterDetailPage development. But facing issue to push new ContentPage to Detail
If I am using code behind than no issue, I can do like below
private void Button_Clicked(object sender, System.EventArgs e)
{
Detail= new NavigationPage(new Menu1Page());
}
But when it comes to Mvvm in ViewModel I don't have Detail page access there. So I can this, but it is hiding MasterDetailPage
async Task Menu1Page()
{
await Xamarin.Forms.Application.Current.MainPage.Navigation.PushModalAsync(new Menu1Page());
}
So, how can push pages to Detail from Mvvm?

You can access Detail page too in ViewModel. Just you need to cast App.Current.MainPage as MasterDetailPage. Look at code below.
async Task NavigateNext()
{
await (App.Current.MainPage as MasterDetailPage).Detail.Navigation.PushAsync(new Menu1Page());
//(App.Current.MainPage as MasterDetailPage).IsPresented = false;
}
The above code snippet pushing pages as child of MasterDetailPage so that you can go back by pressing back arrow on Navigationbar.
You can set pages directly to Detail page, it shows pages at a first page of MasterDetailPage in this scenario back arrow wont be available to go back, like below
(App.Current.MainPage as MasterDetailPage).Detail = new NavigationPage(new Menu1Page());
//(App.Current.MainPage as MasterDetailPage).IsPresented = false;

By default, no.
You need to define BindingContext for the page, and use code-behind navigation.
Or use NavigationService, more details Enterprise App Navigation
Or use any Mvvm framework for this.

Related

Why does OnAppearing not fire every time in Android

I have a Xamarin project. When I run in UWP OnAppearing initially fires once and then loads the Login Page. After successfully logging in, my Main page fires OnAppearing again and I load data into my ViewModel.
However, if I run the project in Android, OnAppearing only fires once - When the Main page initially loads.
protected override async void OnAppearing()
{
if (!App.IsUserLoggedIn)
{
await App.NavigationService.NavigateModalAsync(PageNames.LoginPage, false);
}
else
{
((SchedulerViewModel)Schedule.BindingContext).LoadData();
}
base.OnAppearing();
}
Why does Android only fire once? Or is UWP the one misbehaving?
NOTE: NavigationService is not a standard Xamarin Forms class. I assume it is built on top of Page.Navigation.PushModalAsync and PopModalAsync.
This is documented behavior of Modal Stack on Android:
Popping Pages from the Modal Stack:
When PopModalAsync is invoked, the following events occur:
...
The page being returned to has its OnAppearing override invoked, provided that the underlying platform isn't Android.
NOTE: it seems to depend on the API version of Android. I just tested it on API 30, and Android did fire OnAppearing again, when modal page was popped.
Instead of code in OnAppearing, I would solve it like this:
In App.xaml.cs, instead of:
MainPage = new MainPage();
do:
if (!App.IsUserLoggedIn)
MainPage = new LoginPage();
else
MainPage = new MainPage();
Then when LoginPage is done, instead of pop modal, do:
Application.Current.MainPage = new MainPage();
NOTE: Adapt as needed, if these are pages inside NavigationPage or AppShell.

How to best implement a log in page with Caliburn.Micro MVVM

I am new to using caliburn.micro and currently learning MVVM.
I am using the windows template studio to create my UWP app, and it works great! But unfortunately, I am not familiar with MVVM and still learning UWP.
I get how the navigation works etc and how the shellpage is loaded. However, I want to prompt the user to log in upon opening the app (i.e. a login in page will start with no navigation sidebar).
I also want to make sure I'm following best practices...
I have tried substituting the MainViewModel with LoginViewModel which I get works, however, I don't want to create the navigation pane. I get that this is triggered by the "new Lazy(CreateShell)". I'm just not sure if I want to remove this from the activation service and call a method upon login?
Below is the default code supplied by the windows template studio which triggers on activation of the app if I understand correctly.
private ActivationService CreateActivationService()
{
return new ActivationService(_container, typeof(ViewModels.LoginViewModel), new Lazy<UIElement>(CreateShell));
}
private UIElement CreateShell()
{
var shellPage = new Views.ShellPage();
_container.RegisterInstance(typeof(IConnectedAnimationService), nameof(IConnectedAnimationService), new ConnectedAnimationService(shellPage.GetFrame()));
return shellPage;
}
I just need to be pointed in the right direction or lead to a video/tutorial as I'm struggling!!! any help much appreciated.
If you want to show login page,you can remove the ShellPage.It is a navigation view.
in App.xaml.cs
private ActivationService CreateActivationService()
{​
return new ActivationService(this, typeof(LoginPage));​
}​
​
private UIElement CreateShell()​
{​
return new Views.ShellPage();​
}
When login successfully,if you want to show the navigation view,you can set the ShellPage to the content of current window.
Window.Current.Content = new Views.ShellPage();

How to re-instantiate page/viewmodel in UWP?

I using MvvmCross to build my UWP application. I have views with their own view models.
When I start the app then first time from Setting view navigate to Passcode view using ShowViewModel<PasscodeViewModel>(). Then it call view model and view constructor to build and initialize view. When user come back to setting view and again navigate to passcode view using same method like ShowViewModel<PasscodeViewModel>() then this time view and view model constructor not get called. Since unable to reinitialize passcode view. So it display previous instance of passcode view.
Following solution I have tried
I tried removing the backstack in the navigations but then also not constructor get call.
Also implement loaded event but this solution also not working for me.
Also implemented Void Init() in view model but this method also not get call.
I just want when I navigate to PasscodeView then each time it call constructor of PasscodeView and PasscodeViewModel.
So my question is how to force to re-initialize page and viewmodel each time while navigation??
Please help to resolve this issue.
I needed to use navigation cache mode on required.
I resolved it for me with the not very clean solution to call init again.
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (this.ViewModel!= null && e.NavigationMode != NavigationMode.Back)
{
var reqData = (string)e.Parameter;
var converter = Mvx.Resolve<IMvxNavigationSerializer>();
var req = converter.Serializer.DeserializeObject<MvxViewModelRequest>(reqData);
this.Vm.CallBundleMethods("Init", new MvxBundle(req.ParameterValues));
}
base.OnNavigatedTo(e);
}
This code avoids to call init again on back navigation.
I just set Universal Windows Phone apps page navigation cache mode "Disabled". I think its default value is "Required".
public PasscodeView()
{
InitializeComponent();
NavigationCacheMode = NavigationCacheMode.Disabled;
}
The above code work for me.

Which event is fired when Content property is changed

I have two Pages ProductSearch,ProductDetail and Im changing the Content property to Navigate between Pages. I want to know if any events are fired so I can write some code in it?
On ProductDetail Page I have UIElement property
public UIElement MainContent { get; set; }
On ProductSearch Page I Navigate to ProductDetail By setting the Content property like this:
private void OnGetDetailsClick(object sender, RoutedEventArgs e)
{
ProductDetail productDetail = new ProductDetail();
productDetail.MainContent = this.Content;
this.Content = productDetail;
}
On ProductDetail Page's Back Button I navigate back to ProductSearch:
private void OnBackButtonClick(object sender, RoutedEventArgs e)
{
this.Content = MainContent;
}
Now I want to know how can I call a method when I navigate Back to ProductSearch Page i.e how would I know that I have Navigated from ProductDetail Page? I tried to check if it loads the page but found out that When you change content of control it doesn't fire the load event of the page. Any solution?
Yea this will not execute the load event since your are only changing the content obviously.
if you want to take advantage of navigation you should check out this video. Even if its done with blend the concepts apply also with Visual STudio: https://vimeo.com/6599527 (Simple Silverlight Master/Detail Navigation App with Blend 3)
You should check out articles on master detail binding like this one: https://msdn.microsoft.com/en-us/library/cc645060(v=vs.95).aspx
The key is to take advantage of the powerful binding concepts which come with silverlight. And if you are not using deep linking you might want to consider using a user control to hide/show details instead of a extra page.
HTH

How to create a page in Code behind and navigate the main page to created page in Windows Store app?

I need to create a page in Code behind and navigate the main page to created page in Windows Store app
I tried this but its not working the black page is navigated
Page p1 = new Page();
p1.Content = pdfViewer1;
this.Frame.Navigate(typeof(Page),p1);
Navigating to a page created entirely in code behind is very tricky. I am not even sure it is possible to do (at least without some complex hack) This is due to the fact that Visual studio builds some classes behind the scene to ensure the navigation especially the class "XamlTypeInfoProvider" which is used to identify the pages to which navigation is possible.
According to me, the easiest way to navigate to a page created in code behind is to create a "normal" blank page and then to fill this blank page with content created in code behind.
// create the page content in code: here it is in the variable pdfviewer
this.Frame.Navigate(typeof(BlankPage1),pdfViewer);
and within the "blank page" use the OnNavigatedTo event to put the created page content on the screen
public sealed partial class BlankPage1 : Page
{
public BlankPage1()
{
this.InitializeComponent();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
(this.Content as Grid).Children.Add( e.Parameter as UIElement);
base.OnNavigatedTo(e);
}
}
You'll need to make sure you're using the correct Frame object. From what you've provided, it looks like you need to use the "root" frame, much as is done when your main window is loaded in your app's OnLaunched override.
Here's an example of launching a secondary page from a main page.
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
Loaded += MainPage_Loaded;
}
void MainPage_Loaded(object sender, RoutedEventArgs e)
{
Frame rootFrame = Window.Current.Content as Frame;
rootFrame.Navigate(typeof(SecondaryPage));
}
}
Note that what you pass to Navigate is the type of the Page object, not an instance of it. Navigate will create an instance and navigate to it. The new page's Loaded handler can then connect up any additional content, such as the PDF viewer shown in your code. If necessary, you can pass arguments to the secondary page by using one of the other Navigate overloads.

Categories