I have a little problem. I have to make an app in UWP, and I have to send an item to other page while staying on the same page. And I have no idea how to acomplish that. I have tried different things, but I always ended up on transfering my List to the page, and also transfering view to thta page.
I would really apreciate your help.
If you want to pass parameters when navigating to the page, you can use the following method:
If you don't use the Frame control for navigation
var frame = Window.Current.Content as Frame;
frame.Navigate(typeof(MyPage), myItem);
If you use the Frame control for navigation
frame.Navigate(typeof(MyPage), myItem);
If you are not passing parameters through navigation, you are passing data to another page in the current page. Then we can achieve this in another way.
Suppose we want to modify the data of the parentPage in the childPage, we can add a static object when navigating to the parentPage.
public static MainPage Current;
public MainPage()
{
this.InitializeComponent();
Current = this;
}
public void doSomething(string param)
{
// do something...
}
In other pages, we can make some modifications by accessing this object:
MainPage.Current.doSomething("Hello");
Related
I'd like to pre-load the ShellPage in a WinUI 3 (v1.1.5) Desktop application. That is, during Activation (called by
await App.GetService<IActivationService>().ActivateAsync(args);
in the OnLaunched handler of the App class), I'd like to make sure ShellPage is loaded before any of the navigation pages are displayed. I've changed the service configuration to include
services.AddSingleton<ShellPage>();
services.AddSingleton<ShellViewModel>();
in the constructor for the App class which should mean only one of each of ShellPage and ShellViewModel will be instantiated for the app run but the question is when are they fully provisioned?
The normal progression is that the Activation step first assigns ShellPage to MainWindow.Content, then navigates to MainPage (these are the names for the default project). Because MainPage is actually loaded into a Frame on ShellPage, it seems layout for MainPage happens before ShellPage layout is completed.
Any idea how I do this on initial startup? This is only an issue when the first Page is presented. After that, ShellPage is reused.
By default, TemplateStudio's navigation re-instantiates pages for every navigation. It doesn't use the ServicesProvider, so registering your pages as singleton won't help.
If you want to keep your page instances, you need to set NavigationCacheMode="Required" on your pages. This way, your pages will be cached even after you navigate away.
Still, your pages won't be instantiated until you navigate to them once at least. In order to instantiate all of your pages at the very beginning, you need to navigate through them at least once.
You can get all the NavigationViewItems with a method like this.
private static IEnumerable<NavigationViewItem> GetNavigationViewItems(IEnumerable<object> items)
{
foreach (var item in items.OfType<NavigationViewItem>())
{
yield return item;
foreach (var grandChild in GetNavigationViewItems(item.MenuItems.OfType<NavigationViewItem>()))
{
yield return grandChild;
}
}
}
And use it like this in the NavigationViewService's Initialize method.
[MemberNotNull(nameof(_navigationView))]
public void Initialize(NavigationView navigationView)
{
_navigationView = navigationView;
_navigationView.BackRequested += OnBackRequested;
_navigationView.ItemInvoked += OnItemInvoked;
IEnumerable<NavigationViewItem> menuItems =
GetNavigationViewItems(_navigationView.MenuItems);
foreach (var item in menuItems)
{
if (item.GetValue(NavigationHelper.NavigateToProperty) is string pageKey)
{
_navigationService.NavigateTo(pageKey);
}
}
}
A little clarification first, and then the answer I found to the issue.
Andrew's answer (above) is great for instantiating all of the Pages in the NavigationView at startup but the very first page loaded still would not have access to a fully loaded ShellPage in its constructor (and thus, a fully populated element tree). Andrew is right that the NavigationViewItems (Pages) don't persist by default, but the ShellPage does as it's part of the UI. Specifically, it is the content of the MainWindow and defines a Frame into which NavigationViewItems are loaded. Regardless of which Page is displayed, it's the same instance of the ShellPage people see.
The issue arises because of the order in which Activation (specifically, the DefaultActivationHandler) is done at App startup. When the App starts, it calls
await App.GetService<IActivationService>().ActivateAsync(args);
which does
// Set the MainWindow Content.
if (App.MainWindow.Content == null)
{
_shell = App.GetService<ShellPage>();
App.MainWindow.Content = _shell ?? new Frame();
}
and navigates to the first Page (loads the first Page into the NavigationView.Frame by calling DefaultActivationHandler) before finishing the loading of ShellPage. Thus, ShellPage is not fully loaded (ShellPage.IsLoaded == false) when MainPage is loaded.
To fully instantiate ShellPage before any of the NavigationViewItem Pages are loaded, simply change the loading sequence. First, defer the navigation to the first page (whichever you choose) by editing HandleInternalAsync in DefaultActivationHandler.cs to
protected async override Task HandleInternalAsync(LaunchActivatedEventArgs args)
{
//_navigationService.NavigateTo(typeof(MainViewModel).FullName!, args.Arguments);
await Task.CompletedTask;
}
Move the navigation to the OnLoaded handler in ShellPage.xaml.cs:
private void OnLoaded(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
{
TitleBarHelper.UpdateTitleBar(RequestedTheme);
KeyboardAccelerators.Add(BuildKeyboardAccelerator(VirtualKey.Left, VirtualKeyModifiers.Menu));
KeyboardAccelerators.Add(BuildKeyboardAccelerator(VirtualKey.GoBack));
App.GetService<INavigationService>().NavigateTo(typeof(MainViewModel).FullName!);
}
All Pages now receive a loaded ShellPage when navigated to, regardless of order.
In my Xamarin.Forms Prism app, I am using a MasterDetailPage for navigation.
While I am on one detail page, I would like to navigate to another detail page, as if I had selected it from the master page.
Initial navigation in App.xaml.cs:
protected override void OnInitialized()
{
...
NavigationService.NavigateAsync("MainPage/RootNavigation/MyFirstPage");
}
When I click a shortcut button on MyFirstPage, I would like to go to MainPage/RootNavigation/MySecondPage. The closest that I have been able to achieve has been using an absolute Uri.
private async void OnShortcutTapped(MyModel sender)
{
...
await _navigationService.NavigateAsync(new Uri("http://myapp.com/MainPage/RootNavigation/MySecondPage", UriKind.Absolute), navigationParams, null, false);
}
This basically gets me what I want, but after navigating in this manner, if I make the Master visible and select the menu item for MySecondPage, it refreshes the detail page as if it is navigating to the page.
Is there a better way to maintain this navigation, so that the master page knows that MySecondPage is already being displayed and it doesn't try to reload it?
While your navigation pattern doesn't make a lot of sense to me, you can achieve what you want by invoking a navigate command in the MasterDetailPageViewModel. You have a number of ways to do this. You could use the IEventAggregator to send a message to the MasterDetailPageViewModel to navigate, or you can use a CompositeCommand that invokes a DelegateCommand that exists on the MasterDetailPageViewModel.
You can see a sample of using a CompositeCommand here: https://github.com/PrismLibrary/Prism-Samples-Forms/tree/master/UsingCompositeCommands
You can also see how to send messages in this sample that I gave at the Xamarin Evolve conference: https://github.com/brianlagunas/Evolve2016SamplesAndSlides
Another option would be to just call a navigate command off the App.Current.MainPage ViewModel from with your MyFirstPage code behind.
I am creating a Quiz program which contains many subjects. But I struck at the following stage. I created many pages and want to load them based on the subject selected. But I don't know how to make it.
Here is what I wanted.
Here Play,Settings and Exit are buttons in main screen. Once you click Play it will show you different subjects available. Once you select the subjects you have different options too.
at first I created Single page and I used grids with hide and show options. But its kind of buggy. So I created pages but I don't know how to navigate between the pages.
How can I achieve it.?
#Ajit,
Yes you can navigate between Pages using :
currentFrame.Navigate(typeof(NextPage));
If currentPage is not this, you can find it the following helper class.
It allows to navigate, even from a ViewModel class :
public class NavigationExtension
{
public static void Navigate(Type typeOfPage)
{
Windows.UI.Xaml.Window window = Windows.UI.Xaml.Window.Current;
if (window != null)
{
Windows.UI.Xaml.Controls.Frame frame = window.Content as Windows.UI.Xaml.Controls.Frame;
if (frame != null)
{
frame.Navigate(typeOfPage);
}
}
}
}
Regards
If you want to go to another page and don't want to come back,
use this code:
Frame rootFrame = Window.Current.Content as Frame;
rootFrame.Navigate(typeof(Your Page Name));
I have a page X in a Windows Store App (Windows 8.1) that gets shown after the splash screen. I want to evaluate something while / after the page loads, before the user can interact with the page.
Depending on the evaluation I want to do one of the two:
Just show the page X to the user and only navigate to page Y when the user clicks a button
Skip the current page and navigate to page Y automatically
1 works fine.
2 doesn't. I tried with calling this.Frame.Navigate(typeof(Y)) in the constructor, which didn't work because this.Frame was still null. Then I tried calling it in LoadState and OnNavigatedTo, but while in both cases this.Frame is not null, the Navigate() method returns false, which means the navigation fails. I tried to step into the method in Debugging, but it didn't work (?).
One hint is, that when hitting a breakpoint in the Navigate() code line when it gets called automatically, the screen still shows the splash screen, so it seems the UI elements have not been loaded yet. So the final question is: How can I do the evaulation and automatic navigation with all elements being loaded (or just so that it works)?
I don't see why you would call Frame.Navigate(...) in OnNavigatedFrom, but I can suggest two options that work for me:
Navigate to the second page in OnNavigatedTo: Although this doesn't work out of the box, it does when instructing the dispatcher to do the navigation:
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
this.Frame.Navigate(typeof(SecondPage));
});
}
}
An even easier solution is to do the navigation within the first page's Loaded event:
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
this.Loaded += (sender, args) =>
{
this.Frame.Navigate(typeof(SecondPage));
};
}
}
Of course, in both cases you can add whatever calculation you like within the lambda expression before calling Frame.Navigate(...)
EDIT: As a third alternative, maybe you should think about moving the calculation and decision part to OnLaunched in App.xaml.cs, and load either the first or the second page as root page, instead of opening the first page and immediately navigating on to the second?
I am working on a Windows Phone application, here is the scenario that I have problem:
So I have three pages, lets call it page 1, 2, 3.
In page 1, I have a button called start downloading. Click the button and use NavigateService.Navigate(page2Uri) and navigate to page2.
Page 2 makes query and downloads images from internet, so in its OnNavigateTo handler, I check the page back stack, if it is navigated from page 1, I will do the download. In the app bar of this page, I have a button that can navigate to page3.
Page 3 is a list of options that will perform some behavior on the image that is downloaded in page2. Once I choose an option, I want to go back to page 2 and perform some behavior on the loaded image.Here the question comes: if I use NavigateService.Navigate(page2Uri) to navigate from page3 to page2, it will call the Page2 constructor and OnNavigateTo handler again, which will cause it to lose every instance variable it already got.
But if I use NavigatService.GoBack it will go back to page2, then realizes that the backstack top entry is page1 (since page1 -> page2 -> page3). So it will re-download everything again.
I dont want anything to be downloaded again when navigate back form page3 to page2. So wondering if anyone has good idea about this.
Thank you.
You can use the query parameters and NavigationEventArgs to help.
First, you can use the NavigationEventArgs to determine if the user is going forward or background by checking the NavigationMode.
Second, you can tell page 2 to download by using the query parameters.
From page1:
private void MoveToPage2FromPage1()
{
NavigationService.Navigate(new Uri("/Page2.xaml?shouldDownload=true", UriKind.Relative));
}
and page2:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (e.NavigationMode == NavigationMode.Back) return;
string shouldDownload = ""; //May not be needed if you'll only ever go to page 2 from page 1 to download...
if (NavigationContext.QueryString.TryGetValue("shouldDownload", out shouldDownload))
{
Convert.ToBoolean(shouldDownload);
}
}
There are several ways to pass data to another page:
You can use query parameters as Shawn suggested.
You can use global data stored somewhere like in app.cs
You can use a static class to hold the data.
You can use a shared viewModel to hold the parameters. (or static properties in the viewmodel)
It all depends on the particular case. I think Shawns suggestion of using query paramaters is probably the most 'correct' MVVM way, but the other methods have their place.
You need to implement the following function and the navigation service.
These code will definitely solve your problem
for two or more parameters, use this code
String download="true";
String file="image";
NavigationService.Navigate(new Uri("/Page3.xaml?download="+download+"&file="+file+"", UriKind.Relative));
OnNavigatedTo, add the following code on to your Page2
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
String download=NavigationContext.QueryString["download"];
String file=NavigationContext.QueryString["file"];
}
For the above OnNavigatedTo function outputs true and image. You can use MessageBox.Show(); to output