My problem is that I want to know when the user navigated to the page and when navigated away. So I can perform some page specific tasks like subscribing and unsubscribing to events.
Previously it was obvious and we could override OnNavigatedTo and OnNavigatingFrom methods. But in Windows Phone Runtime, there is no guarantee those methods occur when the user switches between apps for example.
In Windows Phone Runtime, how to know when the user is opening a page and when going away (to another page, start screen or another app)?
When you navigate to another page - it's simple, you handle NavigatingFrom/NavigatedTo. When not - it's also simple - you shouldn't be getting these events and so you should do nothing in most cases. I've seen NavigatingFrom being raised though in certain circumstances when the app was getting suspended and navigation state was being read from the Frame even though technically in-app navigation wasn't occurring and there would be no matching NavigatedTo event on resume. You might want to filter that out by setting and clearing some flag in the Suspending event (or Application.OnSuspending override) before and after NavigatingFrom is triggered and then ignoring it in the page NavigatingFrom handler for certain code. You would probably still want to save the page state in that event, but not unsubscribe from other events in case the app gets resumed before it gets terminated.
Application.Suspending/Resuming are some events you might also be interested in for saving/loading overall app state or refreshing data, though maybe less so for subscribing/unsubscribing from events since most of these should be fine to leave alone when the app gets suspended which happens when you switch to another app.
Page.Loaded/Unloaded events are ones you would handle if you want to touch parts of the UI that need to actually be loaded in the visual tree, since NavigatedTo happens before the page is loaded.
Related
What is the real order of events in a Windows Forms application?
What I mean is, when I put code in the Form_Shown event, I expect that code only to run after the form has been Shown:
verb (used with object), showed, shown or showed, showing. 1. to cause
or allow to be seen... - http://dictionary.reference.com/browse/shown
But the Form_Shown event is a little misleading. If I do some heavy stuff inside that event, it seems as though the code gets executed before the Form has finished been shown. Let's say that I have a MainMenu, a small Toolbar and a TextBox on a form.
I want to do some heavy stuff (nevermind threads and workers for now...), so the last event I can use I would think would be Form_Shown. So I put my heavy code in there, but when the Form begins to display, I end up waiting ~ 5 - 6 seconds for the Toolbar and stuff to display (which ends up happening after my heavy code does its thing.
Which leads me to believe that I'm subscribing to the wrong event. I don't want the Form_Shown event at all. What I really need is:
Form_WhenALLTheThingsHaveShownEventHandler event.
So, how can I know _when all the things (controls) have been fully loaded and displayed?
The Shown event is in fact the last event related to initialization that is raised. However, note that the actual rendering (drawing on-screen) of UI objects in Windows (and on other platforms) is deferred. The creation of a UI object merely allocates all the necessary resources and "invalidates" the visual area of the object. The platform then later schedules the rendering event (in unmanaged Windows, this is WM_PAINT, in the Winforms API this would be the Paint event for a Control instance).
The rendering event cannot be dispatched until the UI object's thread is available, and if you have long-running code in the Shown event, that will keep the UI object's thread unavailable for the duration of your code. I.e. nothing gets drawn until your code completes.
There are other events that you could use to more reliably detect when things have "settled down". For example, the Application.Idle event tells you when the main application thread is about to enter the idle state. Alternatively, you could just subscribe to the form's Paint event. In either case, you would want to use BeginInvoke() to dispatch your long-running code, so that you don't block the handling of those events.
Now, all that said: you really should not be performing any long-running work in the UI thread, period. Using either of the above events doesn't solve the underlying problem; it simply delays the problem until after the initial rendering of your UI. The UI will still remain blocked while your long-running work is executing, and frankly the user may actually find it preferable for there to be no UI at all, than for there to be something that looks like they can interact with but which they can't (i.e. is unresponsive to their input).
In the latest version of .NET, there are some very nice mechanisms available for shifting long-running work to background threads, so that the UI can remain responsive. See Task and the async and await keywords in C#. You could instead use the older BackgroundWorker object to accomplish the same, if you prefer.
I'm using the FilePicker for Windows Universal apps and I'm trying to launch the File Picker from MainPage.xaml and then navigate to a different page (LoadPhoto.xaml) to render the selected image.
I initially implemented my app so that I'd navigate to LoadPhoto.xaml and then, as part of loading the page, I'd call the File Picker. However that caused issues when resuming the app, so I moved the File Picker call out of the constructor.
In the newest implementation, I call the file picker from MainPage.xaml and then, if a photo has been selected, navigate to LoadPhoto.xaml. However, there seems to be a race condition somewhere: Sometimes, the app stays on the MainPage after selecting a picture (it looks like it's actually navigating to the LoadPhoto page but something makes the Frame go back to the MainPage). Other times, the app successfully navigates to the LoadPhoto page and renders the image, but if I navigate back with the Back button and then press the Pick photo button again, the FilePicker is briefly shown and then the app crashes. This behavior doesn't repro with VS attached. Everything works fine while executing in Debug mode.
I think the root cause is that the ContinueFileOpenPicker code is executed from a worker thread, so I shouldn't call this.Frame.Navigate(typeof(LoadPhoto), file); from that thread. That call should be made from the main thread, but I'm not sure how to do that.
Unfortunately, this doesn't fix the issue: await CoreWindow.GetForCurrentThread().Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { this.Frame.Navigate(typeof(LoadPhoto), file); });
How can I navigate to a different page from the ContinueFileOpenPicker method? The full code with the repro is here.
When you call to Frame.Navigate to go to the LoadPhoto page you are passing a complex object as a parameter: the file the user has picked. When you go back to MainPage and start a new picker session your app gets suspended and SuspensionManager serializes the frame's state (see SaveFrameNavigationState method in that class). Unfortunately, the GetNavigationState method in Frame does not support serializing a complex object, but only simple ones like strings, integers or guids. This is documented in the Frame.Navigate method on MSDN.
The reason you don't see the app crashing when you are debugging in VS is because (by default) the app doesn't get suspended in this scenario, so the code that throws the exception is never called. However, with no debugger attached, your app is suspended when you navigate away from it. To force the suspension, use the Lifecycle Events drop-down in the Debug Location toolbar once you have launched the picker session.
If you really need to save/restore the state of the frame, then you should avoid passing StorageFiles when navigating. You can use FutureAccessList, pass the path to the file when navigating and load it in LoadPhoto.
If you don't need (or want to use) what SuspensionManager has to offer, then you could get rid of it and keep passing a StorageFile object. However, keep in mind that if you do this a reference to that object will be kept in the navigation stack.
I know that in Desktop apps we have things like Form_Closing which is great for doing stuff before the app shuts down, but I need to do things before a Metro app shuts down (is closed by the user or the system) and I can't get this working.
The only events that seem to be even remotely related are the App_Suspending and pageRoot_Unloaded events.
My problem is that my code (any code at all) never gets called if I put it in the Unloaded event, which makes me believe that the Unloaded event never gets fired.
I haven't tried using the Suspending event yet because I need to do this work when the app is actually closing, or about to be closed, not just suspended.
Any ideas?
There is no diff between Closing and Suspending Metro App on the moment of suspending, so you must save state in OnSuspending override every time. But after re-Activating you can see what was happened with your App (OnLaunched (for example, here you can see value ClosedByUser)).
Here is not bad article about WinRT LifeCycle.
you can override OnNavigatedFrom method which will be invokved when page is being navigated away from.
http://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.xaml.controls.page.onnavigatedfrom.aspx
I dont think there is any explicit calls for app being terminated (accept checking the previous state in app.xaml.cs)
I'm currently working on an application that uses a Windows Form GUI. The main work of the application will be performed on an additional thread - but it is possible that it will be dependent on the state of the form.
Because of this, before I create the thread I must make sure that the form is completely loaded. Also, I need to make sure the thread is terminated before the form begins closing.
Possible solutions for this problem might be overriding the OnShown and OnFormClosing methods.
Does the OnShow method really gets called only after ALL of the assets of the form have been loaded? And what about the OnFormClosing - can I be sure that any code executed in this method will be performed before the form begins close / dispose?
I suggest you read through the WinForms event ordering as posted on MSDN:
http://msdn.microsoft.com/en-us/library/86faxx0d.aspx
Windows Forms events can be tricky, and the order they fire unreliable. For example, the 'Shown' event is meant to fire once and once only, when the Form is first displayed, but just yesterday I found a way to completely prevent that event from firing by manipulating Form.Visible flags at the right time.
So, you need to be quite specific about your needs. For example - when you say 'completely loaded', what do you mean? Controls created, form visible, Form constructor finished executing?
Likewise, the FormClosing event might be circumvented by an unhandled exception in your main aUI thread, which results in the Form being removed without the event firing.
I suggest never assuming anything around these events. Make your worker thread capable of dealing with the Form state being unavailable, or not ready. Without knowing your exact requirements, it's hard to be more specific.
Have you tried to use InitializeComponent on the constructor of your main WinForm and use OnLoad (called whenever everything is loaded)?
My basic issue is this, I have events firing on pages I've left based on network activity that are causing problems when I thought the old forms were being destroyed.
More detailed information: I am writing a windows phone app that communicates with a network player. I have a static instance of my communication class in my App class so all the forms can share the connection, and all my forms subscribe to it and process results within that form. From a main menu you can choose one type of source and it opens a file browsing form that refreshes a listbox as you navigate, cancels the back button and refreshes the new contents to simulate file navigation until you are the root folder. The app doesn't know if you're clicking on a file or folder, it gets a network message when media starts playing and watch for that and then navigate to a "play" form. I had been using all .Navigate's for this until now and it worked great until I added another branch off the main menu for a new source. Although the new source is completely different, the device sends a lot of the same generic commands which just mean something else in the current context. After visiting the my file browser form and going to my new source, a play command from the network, which means something else now, would cause my to jump into my old "play" form from the previous source as if I was still on the file browser form, which isn't intended.
So I've tried many things and have it kind of working now but it's message and I lose some features. Currently I changed from using all .navigates, also in the back button override, to trying to use the stack and navigate.goback's. I pass variables when needed using globals in App and unhook my net listeners from the form, goback, and then connect them in the new form's listeners in it' navigatedto. I think there is timing issue though as in some cases I needed to send a command to the media box as it's changing and it ended up triggering the wrong event handler again. I think the easiest solution, if possible, and they way I though it would work is if each time I navigated from the form it old one, it's handlers, etc were all destroyed and I didn't have to use the stack at all, handling all the back buttons myself.
I know that's a long description and thanks if you made it this far, hopefully it made some kind of sense. Does anyone have any suggestions on what I can do?
As a side note I'm a long time self-taught VB programmer who has been stuck in .net 2.0/winforms and I've just now made the move to C#, OOPs, and XAML to write my first Windows Phone app so it's likely I'm doing something stupid or overlooking something obvious...
It is likely because something has retained reference to the form. The most common cause is event handlers.
So, if your static class exposes an event, and you subscribe to that event in a form, you must unsubscribe from the event when your form closes / navigates, otherwise the form will remain in memory....
If that isn't the case, look for something else that is acquiring a reference to your form and not releasing it.
Most likely the problem is based on a bad application architecture, when it comes to handling commands send from the UI.
When you say 'sends a lot of the same generic commands which just mean something else in the current context.' you most likely reveal the source of the problem.
As a workaround, you can define an interface, that your communication class implements. Each form has it's own method it calls on a communication class instance.
If you indeed receive a command from a phone page, that is no longer in view, just don't process it.
You can store the navigation history to always know what page is the only one allowed to send commands to a communication class.