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.
Related
I'm updating a very large Windows Forms app to .Net Maui to make it into a cross platform app. Ideally, I would have the time to rewrite everything, but I don't. The client wants it yesterday. I'm already using a ton of the allotted time replacing the Windows Forms style interface with the XAML version. I've tried not to tinker too much with the code since the app was behaving flawlessly. Still, I've had to make a lot of changes because the Maui controls aren't always accessed the same ways as Windows Form's controls. Almost all of the methods and functions in the original app are synchronous. But some of the .Net Maui functions that I use to replace them are asynchronous. One function that is giving me a lot of trouble is the awaitable DisplayAlert(). Execution moves right onto the next statement in the code without waiting for the alert to be displayed or the user to respond. The function can be made awaitable, but to do this, the entire method within which it appears must be marked Async, which creates its own problems. There are literally hundreds of calls to The Windows Forms version of DisplayAlert(). Any solution that isn't basically a drop in replacement is going to cost tons of time.
I've been trying to create a blocking popup function that waits for the user's response before executing the next line of code within a synchronous block of code. In the XAML markup I've defined a popup "panel" with a frame, two labels and 3 buttons. Ideally, the code behind should be a function with the same parameters and behaviors as DisplayAlert() except that it blocks. It should display the panel, wait for a user response (button click/press), hide the panel, and finally return the text string of the button that was clicked...all within the same function.
Using simple method's like while loops to determine if a button was pressed block the thread from detecting that a button was press. Moving the panel display to a different thread than the button press, does nothing since the panel can only be displayed on the main thread. Invoking on the main thread has not been successful...at least not the way I wrote the code. I'm hoping someone can provide a very simple example of a blocking DisplayAlert() function that can be used within a non-async method.
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.
I'm having trouble developping an app for Windows phone.
Visually, the app is just a panorama displayed via the MainPage, and does nothing else.
All the code must be running in background without the user seeing it.
The app is open via a custom URL scheme which is something like "myscheme://..."
So here I have two questions :
1) How to perform the code in background with just the mainpage displayed on the screen
2) How can I tell the app when it's launched "go to that page" or "go to this page" depending on the URL received ? I have a "AssociationUriMapper" class that is accessed when the app is open via the customURL, and I have the code line
return new Uri("/Authentication.cs", UriKind.Relative);
For example when the app is called by an authentication URL, but it doesnt work and goes to the "navigation failed" function in the App.xaml.cs
Thank you
Once you navigate to the main page, you can override the method :
OnNavigatedTo(NavigationEventArgs e)
Once you land into this function, you can have several classes in you project which serve as the back end logic for you. You can instantiate these classes from this function and carry out all the operations by calling appropriate method from those classes.
Moreover, in this function, you can also check for the Uri which caused the navigation to this page. And you can even seperate out parameters and decide what to do depending upon the parameters which are added in the uri.
In this method, you can check for all the necessary conditions that you wish to check and perform conditional navigation further.
I hope I am taking you in the right direction.
Thanks and Cheers.
I have a WPF Browser Application, it's got a StartupUri="StartPage.xaml"
and in the constructor for that Page I'm checking if it can
connect to a database which is on a server.
Now, if it fails, I'd like to stop loading that Page and navigate to a different one.
Trouble is - "A Page can only get a reference to its NavigationService when Page raises the Loaded event." (http://msdn.microsoft.com/en-us/library/ms750478.aspx)
...and by the time Loaded is raised, the page is already "starting to show",
which means if i navigate to another Page from Loaded event, it'll still show the first Page
(very briefly though) before loading the second Page.
So, how do i prevent this?
Since i know it shouldn't show up early when it's being constructed,
but the NavigationService at that time is null. This wouldn't be a problem if it weren't the first Page to load when my application starts. Maybe i can test the connection in the App: Application class (which is currently empty) and there decide what the StartupUri should be. If that's a good way, please provide a small example.
edit: Excavator
The approach you mentioned - putting the database check in the Application's OnStartup method - would work. But it would be horrible UX to block the UI, pre-startup, while you do a database lookup. Better to navigate first to a splash screen or something, as the startup page, and navigate from there as needed.
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.