Why is NavigationService.Navigate running at the end only? - c#

As you can see, I want to navigate to "ScoreInputDialog.xaml" page, where the user can type in a name. After this I am trying to save the name to a list, but it is always empty because navigation to page "ScoreInputDialog.xaml" is being done at last. How can I navigate to the desired page and get my value before continuing with rest of the code?
NavigationService.Navigate(new Uri("/ScoreInputDialog.xaml", UriKind.Relative)); // Sets tempPlayerName through a textbox.
if (phoneAppService.State.ContainsKey("tmpPlayerName"))
{
object pName;
if (phoneAppService.State.TryGetValue("tmpPlayerName", out pName))
{
tempPlayerName = (string)pName;
}
}
highScorePlayerList.Add(tempPlayerName);

You should do nothing directly after the Navigate call. Instead override the OnNavigatedTo method of the page you are coming from, to get notified when the user comes back:
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
This method will be called when the user exits the "ScoreInputDialog.xaml", probably by pressing the back button or because you call NavigationService.GoBack(). This exits the "ScoreInputDialog.xaml" page and goes to the previous page, where the OnNavigatedTo will be called. This is the time to check for the value.
Illustration of the navigation flow:
"OriginPage" ---[Navigate]---> "ScoreInputDialog" ---[GoBack() or Back-button]---> "OriginPage" (*)
Where the (*) is there the OnNavigatedTo will be called. The implementation could look like this:
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
if (phoneAppService.State.ContainsKey("tmpPlayerName"))
{
object pName;
if (phoneAppService.State.TryGetValue("tmpPlayerName", out pName))
{
tempPlayerName = (string)pName;
}
highScorePlayerList.Add(tempPlayerName);
}
}
Remember to clear the temp player name before calling Navigate:
phoneAppService.State.Remove("tmpPlayerName");
NavigationService.Navigate(new Uri("/ScoreInputDialog.xaml", UriKind.Relative));
Note: OnNavigatedTo will also be called when the user sees the page the first time or navigates back from other pages than "ScoreInputDialog.xaml". But then the "tmpPlayerName" value will not be set.

Navigate isn't being performed last, it is just happening asynchronously. You have to wait for the navigation to complete.
http://msdn.microsoft.com/en-us/library/system.windows.navigation.navigationservice.navigated.aspx

Read the following page : http://msdn.microsoft.com/en-us/library/ms615507.aspx
At the bottom after the Methods and Properties definitions in the "Remark" part it explains how the NavigationService Class works and this nice little graphic explains a lot :

Related

Trigger event on aspx page from .cs file without stopping current execution

I have an aspx page which posts a form back to itself, processes the form in a .cs page (in the DLL, not code behind) and then the code takes one of many branches based on that outcome.
This is a rough outline of what happens:
protected void Page_Load(object sender, EventArgs e)
{
LoanApplication oLoanApplication = new LoanApplication();
string sStep = Request.Form["step"];
oLoanApplication.Process(Request.Form); //Sets the value of the object
}
Then, in the Process method that is in the DLL code, I want it to trigger an event at this point:
public void Process(NameValueCollection pFormData)
{
SendApplicationToWebService();
//Trigger event here on aspx page
}
Basically I am trying to pass a variable returned from the SendApplicationToWebService(); into Google Tag manager.
There are many different branches the code could take, and I do not think it is a good solution to do it at the end - it is best to do it at the point the variable is assigned its value - that way I know all code is passing through this point.
Some of the branches redirect to different pages, so I cannot do this after the process method is called on the Page_Load because the code may never be executed.
Any ideas?
Why don't you pass a callback function to oLoanApplication.Process ?
take a look on this sample

Automatic navigation to next page fails in Windows Store App

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?

Multiple frames of the same type Windows 8 c#

I have an application for Windows 8 with a page (Frame) for displaying a list of items and a page for downloading & displaying the items details. I am also using MVVM Light for sending notifications.
Application use goes something like this:
Open Main Page
Navigate to List Page
Frame.Navigate(typeof(MyPage));
Choose Item
//Complete logic
Frame.GoBack();
Back on Main Page, I start downloading the file in the view model, I send ONE NotificationMessage saying BeginDownloadFile and after it is downloaded ONE NotificationMessage saying EndDownloadFile.
The first time I do steps 2,3, & 4 my NotificationReceived method is hit once, the second twice and so forth.
private async void NotificationMessageReceived(NotificationMessage msg)
{
if (msg.Notification == Notifications.BeginDownloadFile)
{
FileDownloadPopup.IsOpen = true;
}
else if (msg.Notification == Notifications.EndDownloadFile)
{
FileDownloadPopup.IsOpen = false;
}
}
Additional information: I only have one FileDownloadPopup, yet each time, an additional popup is shown each time the NotificationMessageReceived method is called.
My only conclusion is that between navigating forwards and backwards in my app, there are multiple MainPages being created and never closed. This results in many NotificationsMessageReceived methods just waiting for a notification to come their way so they can show their popup.
I have two questions:
1. Does this sound like normal behaviour for a Windows 8 app?
2. How can I close all instances of the MainPage or return to the previous instance without creating a new instance?
Please let me know if I have missed something important out before marking my question down.
This sounds normal to me. The default navigation behaviour in Windows 8 is to create a new page instance each time you navigate to a new page, regardless of whether this is forward or back navigation.
Try setting the NavigatinCacheMode on MainPage to Required. See the MSDN documentation for details of how page caching works.
It sounds like you are registering eventhandlers in the page and then not removing them. Each time you navigate to the page again the handler is being added again in addition to the one you previously added. Try to add your event handler in OnNavigatedTo, and make sure you unregister it in OnNavigatedFrom.
protected override void OnNavigatedTo(Windows.UI.Xaml.Navigation.NavigationEventArgs e)
{
MyEvent.OnDownloadRequest += MyLocalDOwnloadHandler; // add the handler
}
protected override void OnNavigatedFrom(Windows.UI.Xaml.Navigation.NavigationEventArgs e)
{
MyEvent.OnDownloadRequest -= MyLocalDOwnloadHandler; // remove the handler
}

Windows Phone Page Navigation

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

Navigating from App.xaml.cs

I want to add an application bar to multiple pages of my app. So, I'm defining the application bar as an application resource so that it can be used by multiple pages. Now, the event handlers for these buttons are in the App class as mentioned here http://msdn.microsoft.com/en-us/library/hh394043%28v=VS.92%29.aspx.
But, these app bar buttons are basically shortcuts to important pages. So, clicking a button would just take you to the corresponding page. But, since I'm defining the event handlers in App.xaml.cs, it doesn't allow me to navigate. I understand the reason for this. But, I don't know how to solve the problem.
NavigationService.Navigate(new Uri("/Counting.xaml", UriKind.RelativeOrAbsolute));
says "An object reference is required for the non-static field, method or property System.Windows.Navigation.NavigationService.Navigate(System.Uri)"
Does it work if you get access to the frame?
(Application.Current.RootVisual as PhoneApplicationFrame).Navigate(new Uri("/Counting.xaml", UriKind.RelativeOrAbsolute));
Edit:
Each application has only one Frame. It's this frame that exposes the NavigationService. Therefore, the NavigationService is always accessible via the frame since there's always an instance of it in any Windows Phone app. Since you don't usually instantiate a new NavigationService, it's easy to think that it's a static method. However, it's actually a non-static class that gets instantiated automatically when your app is run. All you're doing in this case is getting the global instance, which is attached to the always-present Frame, and using that to navigate between pages. This means your class does not have to instantiate, or explicitly inherit, a NavigationService.
an other way to navigate to an other page from App.xaml.cs (using the app bar) is using the rootFrame var (at the end line):
private Frame rootFrame = null;
protected override async void OnLaunched(LaunchActivatedEventArgs args)
{
...
SettingsPane.GetForCurrentView().CommandsRequested += App_CommandRequested;
}
private void App_CommandRequested(SettingsPane sender, SettingsPaneCommandsRequestedEventArgs args)
{
SettingsCommand cmdSnir = new SettingsCommand("cmd_snir", "Snir's Page",
new Windows.UI.Popups.UICommandInvokedHandler(onSettingsCommand_Clicked));
args.Request.ApplicationCommands.Add(cmdSnir);
}
void onSettingsCommand_Clicked(Windows.UI.Popups.IUICommand command)
{
if (command.Id.ToString() == "cmd_snir")
rootFrame.Navigate(typeof(MainPage)); //, UriKind.RelativeOrAbsolute);
}
I found this approach a better one. The RootFrame object is already in the App.xaml.cs file, you just need to call it. Also putting this in a UI thread dispatcher is safer.
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
// change UI here
RootFrame.Navigate(new Uri("/MainPage.xaml", UriKind.Relative));
});

Categories

Resources