Does Windows Phone 8 NavigationCacheMode = NavigationCacheMode.Disabled is same as windows 8 RT NavigationCacheMode = NavigationCacheMode.Disabled?
if so then, will page that we navigate back to, is created again (constructor is called) in windows phone 8?
if page is created again then how could i reproduce this scenario in simulator (in case of wp8) ?
As far as i am aware, this does not exist in wp8. There are two ways of controlling this behavior,
1) Call any code that you wish to run every time the page loads in the On page navigated to event, as opposed to calling it in the constructor of the page. The "LoadDataFromOnNavigatedTo()" method below will always get executed when the page loads (including from lock screen)
// Constructor
public MainPage()
{
InitializeComponent();
MessageBox.Show("Data Loaded from constructor");
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
MessageBox.Show("Data Loaded from onnavigated to");
base.OnNavigatedTo(e);
}
2) Preferred option is to use an IoC container, such as the one provided in MVVMLight, and take control of when your ViewModels are instantiated. Then you can choose to instantiate them once and re-use application wide scoped, or in a transient way.
Related
Let's consider a two-page Silverlight WP application: the main page PageA, and another PageB we can open from PageA and pass a parameter into it. As Charles Petzold suggests in his bestseller 'Programming WP7', we can instantiate PageB using a statement like this:
NavigationService.Navigate(new Uri(
"/EditEntryPage.xaml?ItemIndex=" + myItemIndex, UriKind.Relative));
And then use the following construct in the OnNavigatedTo/OnNaviagetdFrom events of PageB to process the parameter and the case when the app was tombstoned and reactivated again:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
string myParam;
if (this.NavigationContext.QueryString.TryGetValue("ItemIndex", out myParam))
{
fItemIndex = int.Parse(myParam);
}
else if (PhoneApplicationService.Current.State.ContainsKey(APP_STATE_KEY_ITEM_INDEX))
{
fItemIndex = (int)PhoneApplicationService.Current.State[APP_STATE_KEY_ITEM_INDEX];
}
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
PhoneApplicationService.Current.State[APP_STATE_KEY_ITEM_INDEX] = fItemIndex;
}
However, we have one problem if the user left the app from PageB, the app was tombstoned, and the user returns again to the app to the same PageB using the task manager. In this case, NavigationContext.QueryString in the OnNavigatedTo event returns the same ItemIndex parameter as if the page were called from PageA and the second 'if' is never executed!
Did I miss something important (an app settings, etc), or the behavior was changed in WP8 and we can no longer use this approach?
The query string behavior has not changed from WP7 to WP8. If it is in the uri, it will stay there upon resuming from tombstone or fast app switching.
One method I use to tell the difference is with the NavigationEventArgs.IsNavigationInitiator property. It will be true only when navigating inside your app, and false when you are being resumed from the OS. So if you were to change your first if statment to the following then it may work as you expected:
if (e.IsNavigationInitiator
&& this.NavigationContext.QueryString.TryGetValue("ItemIndex", out myParam))
I´ve a NavigationWindow with some pages. I navigate from one to another with buttons, and go back function of navigation window. My problem is I use a descriptor in some of the pages when they load, and I´d like to dispose it when you use go back function in navigationwindow (in fact the "descriptor" is Kinect, and when the page loads, it starts Kinect with sensor.start(), and I want to stop it when going back, sensor.stop()... but I think it´s the same as a file descriptor for this issue and much more people has worked with file descriptors).
Is there any way to extend the GoBack function in the page to dispose descriptors (in my code I only need to call sensor.stop(); )?
Thanks in advance
My suggestion in the comment was based on windows phone development experience.. but after i tried applying that solution in wpf using navigationwindow, i found nothing like OnNavigatedTo/OnNavigatedFrom in WP/silverlight.
But i found Navigating event of NaviagtionWindow can be used instead. In that event, you can get this.CurrentSource which is Page2 (if you navigate back from Page2 to Page1) and dispose descriptors in that Page.
Hope this work.
Ok, I found how to do a workaround. It also applies to the question: how to dispose an object in WPF. It´s weird all posts about dispose objects in WPF talk about GC and that you can´t dispose it yourself. Yes, GC dispose objects automatically, but when he wants. But maybe you want to dispose inmediately, or you have an object that needs previous operations before dispose. In my case, Kinect needs to be stopped before dispose (you can dispose without stopping, but kinect ir sensor is still working). And GC is not solution because I need to stop it before dispose.
So, the solution:
public partial class MyClass : Page
{
private KinectSensor sensor;
public MyClass()
{
InitializeComponent();
this.Loaded += (s, e) => { NavigationService.Navigating += NavigationService_Navigating; };
// What you want to add to the constructor
// I want to start Kinect
sensor = KinectSensor.KinectSensors.FirstOrDefault(k => k.Status == KinectStatus.Connected);
sensor.Start();
}
public void NavigationService_Navigating(object sender, NavigatingCancelEventArgs e)
{
if (e.NavigationMode == NavigationMode.Back)
{
// What you want to do.
// I want to stop and dispose Kinect
if (sensor != null)
{
sensor.Stop();
sensor.Dispose();
}
}
}
}
If I have two windows in an oob application how do I communicate between them?
This is the new feature of silverlight 5 that allows for multiple windows.
They run in a common application. Hence they share the same static data. The scope of communication choices are therefore very large. Here is an example:-
public class MessageEventArgs : EventArgs
{
public MessageEventArgs(object payload)
{
Payload = payload;
}
public object Payload {get; private set; }
}
public class Messenger
{
private static readonly Messenger _current = new Messenger();
public static Messenger Current { get { return _current; } }
public event EventHandler<MessageEventArgs> MessageReceived;
public void Send(object payload)
{
if (MessageReceived != null)
MessageReceived(this, new MessageEventArgs(payload));
}
}
All windows can attach a handler to Messenger.Current.MessageReceived (just be sure to detach when the window closes) and any window can call Messenger.Current.Send.
Ok so you wouldn't actually use this code its a bit rubbish, the point is Windows in SL5 are not isolated. You can create whatever internal application communication mechanism you need.
Option 1: MVVM Pattern
Both windows share a reference to the same view-model. Changes made by one are seen by both.
Option 2: Normal references
Window A can how a refernce to Windows B when it creates it.
Option 3: Message Passing
You can have a global event that you subscribe to in the Load event. (Make sure you unsubscribe in the Unload event or you will leak memory!) Windows can post messages to that event which the other windows listen for.
As part of my App's startup procedure, it checks data integrity, and if it finds a problem it pops up a message to the user telling them that it might take a while to repair things.
I'm showing the message using MessageBox.Show. Because the data check is done from a worker thread, I'm switching over to the UI thread to make that call, and then setting a ManualResetEvent to tell the worker thread when the user has acknowledged the message.
I kick off the data check/load very early in the app's lifecycle from the constructor in the main Application class, by spinning off a worker thread (using the ThreadPool).
When I run with the debugger, and the message is displayed, the app just waits for input. When I run without the debugger, the app terminates after displaying the dialog for 10 seconds.
That 10 seconds is a big clue - it tells me that the OS thinks the app took too long to initialize (the OS kills apps that take too long to start up).
I think that my MessageBox.Show is blocking the UI thread before the App.RootFrameNavigating has a chance to be invoked.
My questions:
Does my diagnosis sound right?
I'd prefer to kick off my data load early, because it is almost entirely IO, except for this Message Box, and the sooner I can get my Model loaded, the better, but do you normally delay your data load until later in the app lifecycle?
Any other ideas/suggestions? I can't guarantee which page will be the start page, because the app could be resuming to any page. I'm also thinking of having the MessageBox.Show delay itself until the app has initialized, perhaps polling away for a flag set by App.RootFrameNavigating - does that make sense?
I think your problem is a result of kicking off the worker thread in the Application constructor. You should use the appropriate life-cycle event, in this case: PhoneApplicationService.Activated Event
So, the solution I've come up with is to still kick off the data load in a worker-thread from the Application's constructor, but in my PhoneService's class ShowDialog method that I invoke to invoke MessageBox.Show, I check to see if the initial navigation has occurred:
private readonly ManualResetEvent _appInitialized = new ManualResetEvent(false);
public void AppInitialized()
{
_appInitialized.Set();
}
public void ShowDialog(string caption, string text, Action<MessageBoxResult> callback, MessageBoxButton button = MessageBoxButton.OKCancel)
{
_appInitialized.WaitOne();
DispatcherHelper.CheckBeginInvokeOnUI(() =>
{
var result = MessageBox.Show(text, caption, button);
if (callback != null)
{
callback(result);
}
});
}
Then in my Application class:
private bool _firstNavigate = true;
private void RootFrameNavigating(object sender, NavigatingCancelEventArgs e)
{
if (_firstNavigate)
{
_firstNavigate = false;
var navigationService = (NavigationService) sender;
navigationService.Navigated += NavigationServiceNavigated;
}
....
private void NavigationServiceNavigated(object sender, NavigationEventArgs e)
{
var navigationService = (NavigationService)sender;
navigationService.Navigated -= NavigationServiceNavigated;
PhoneServices.Current.AppInitialized();
}
Anyone see any issues with this approach? Anyone come up with a better way?
Is there any possibility to programatically close Silverlight application on Windows Phone 7?
If you write an XNA Game, you will have access to an explicit Exit() method. If you are writing traditional Silverlight project, then NO, there is no way to programatically close your app. See also Peter Torr's Blog entry on Exiting Silverlight Apps in Windows Phone 7. There he also mentions the option of throwing an unhandled exception, which IMO is a terrible programing style.
An option you may try, is using the WP7 Navigation Service to programatically navigate back out of the application. Not sure if that would work though. Why do you need to Exit?
You can always call an exit by doing this at your landing page use this code on click of your application back button:
if (NavigationService.CanGoBack)
{
while (NavigationService.RemoveBackEntry() != null)
{
NavigationService.RemoveBackEntry();
}
}
This will remove back entries from the stack, and you will press a back button it will close the application without any exception.
Short answer for Silverlight is No.
You should not provide a way to close the applicaiton. Closing the applicaiton should be the users choice and implemented by using the back button the appropriate number of times. This is also a marketplace requirement.
That said, a silverlight application will close if there is an unhandled exception. I have seen a few people try and create programmatic closing by throwing a custom error which is explicitly ignored in error handling. This can work but there is still the marketplace issue.
XNA applications can explictly call Exit().
Some good info here already. Adding to this..
The platform is fully capable of managing closure of apps. The more apps don't provide an exit, the quicker users will become accustomed to not thinking about app house keeping, and let the platform manage it.
The user will just navigate their device using start, back, etc.
If the user wants out of the current app to go do something else quickly - easy - they just hit start.
.Exit(), whilst available for xna, really isn't required anymore either. There was a cert requirement during CTP that games had to provide an exit button. This is now gone.
Non game apps never had the need to implement this.
The more this topic's discussed (and it really has been given a good run around the block), the more the indicators to me suggest there is no need to code an exit.
Update: For those thinking of an unhandled exception as a suitable way of closing an app intentionally or letting the app close due to subpar operating conditions, I would recommend reviewing the comments concerning Application Certification Requirements in this answer. Is there a way to programmatically quit my App? (Windows Phone 7)
Here is another solution.
If you have an error page that i.e. displays error to the end user you can use the
protected override void OnBackKeyPress(System.ComponentModel.CancelEventArgs e)
{
base.OnBackKeyPress(e);
e.Cancel = true;
}
And you can instruct user to press start button to exit application.
Add a reference to Microsoft.Xna.Framework.Game, then call:
new Microsoft.Xna.Framework.Game().Exit();
private void PhoneApplicationPage_BackKeyPress(object sender, System.ComponentModel.CancelEventArgs e)
{
while (NavigationService.CanGoBack)
NavigationService.RemoveBackEntry();
}
That works for me fine.
You can close the app using this statement
Application.Current.Terminate();
This worked perfectly on Windows phone 7
System.Reflection.Assembly asmb = System.Reflection.Assembly.Load("Microsoft.Xna.Framework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553");
asmb = System.Reflection.Assembly.Load("Microsoft.Xna.Framework.Game, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553");
Type type = asmb.GetType("Microsoft.Xna.Framework.Game");
object obj = type.GetConstructor(new Type[] { }).Invoke(new object[] { });
type.GetMethod("Exit").Invoke(obj, new object[] { });
Link - source
My 2 pence worth, reasons for an exit
1) there is no interent connection the first time it is run and it needs to create an account on a web service somewhere to run.
2) You need to force an upgrade for the user, again when tied to a web service, you may discover a bug in your app, or have web service changes that mean the user needs to be forced to upgrade, at that point you will want to inform the user that they must upgrade and then exit the app.
Currently in my app I am forced to take the user to a form that says "they" must exit, and if they click back they are again forced back to this page. not very nice.
In Silverlight, I throw an un-handled exception when I have to exit the application. I know that this isn't the graceful method to handle this but it is still the most convenient and easiest solution.
I know that according to the guidelines there shouldn't be any un-handled exceptions in the code but I write why I am explicitly throwing an un-handled exception in the Exception Request document at the time of submission.
Till now this method has always worked and never failed me.
Easiest way to do this is to add a reference to Microsoft.Xna.Framework.Game, then add
using Microsoft.Xna.Framework.GamerServices; before namespace. Then we have a button in our Example.xaml with Click="quit_button". In out Example.xaml.cs we put this code inside our page-class:
private void quit_Click(object sender, EventArgs e)
{
new Microsoft.Xna.Framework.Game().Exit();
//This will close our app
}
var buttonInfo = MessageBox.Show("Are you sure you want to exit?", "Exit", MessageBoxButton.OKCancel);
if (buttonInfo == MessageBoxResult.OK)
{
if (NavigationService.CanGoBack)
{
while (NavigationService.RemoveBackEntry() != null)
{
//
}
}
e.Cancel = false;
}
else
{
//Stop page from navigating
e.Cancel = true;
}
Navigate to App.xaml.cs in your solution explorer and
add a static method to the App class
public static void Exit()
{
App.Current.Terminate();
}
so that you can call it anywhere from your application , as below
App.Exit();