Windows Phone, Prism.StoreApps: How to avoid activation of a certain page after suspension or termination? - windows-phone-8.1

I do want to ensure that in case an app is navigated to a certain page, the app is on another (in my case the previous) page after it was suspended or terminated. In my case the page is for taking photos. I do not want the user to return to this page after the app was in the background since it has no context information. The context information is on the previuos page.
How could I achieve this with Prism.StoreApps?
Background: If an app was just suspended the state of the app remains after it was resumed, hence the last active page is active again. I have no real idea how to set another page active in this case. If an app was terminated Prim.StoreApps restores the navigation state and navigates to the last active view model (hence to the last active page). I do not know either how to alter the navigation state in this case so that another page is navigated to.

In the meantime I fond a working solution myself. Might not be the best and there might be better solutions, but it works.
For resuming the app I handle the Resuming event:
private void OnResuming(object sender, object o)
{
// Check if the current root frame contains the page we do not want to
// be activated after a resume
var rootFrame = Window.Current.Content as Frame;
if (rootFrame != null && rootFrame.CurrentSourcePageType == typeof (NotToBeResumedOnPage))
{
// In case the page we don't want to be activated after a resume would be activated:
// Go back to the previous page (or optionally to another page)
this.NavigationService.GoBack();
}
}
For the page restore after termination I firstly use a property in the App class:
public bool MustPreventNavigationToPageNotToBeResumedOn { get; set; }
public App()
{
this.InitializeComponent();
// We assume that the app was restored from termination and therefore we must prevent navigation
// to the page that should not be navigated to after suspension and termination.
// In OnLaunchApplicationAsync MustPreventNavigationToPageNotToBeResumedOn is set to false since
// OnLaunchApplicationAsync is not invoked when the app was restored from termination.
this.MustPreventNavigationToPageNotToBeResumedOn = true;
this.Resuming += this.OnResuming;
}
protected override Task OnLaunchApplicationAsync(LaunchActivatedEventArgs args)
{
// If the application is launched normally we do not prevent navigation to the
// page that should not be navigated to.
this.MustPreventNavigationToPageNotToBeResumedOn = false;
this.NavigationService.Navigate("Main", null);
return Task.FromResult<object>(null);
}
In OnNavigatedTo of the page I do not want to be activated on a resume I check this property and simply navigate back if it is true (and set the property to false to allow subsequent navigation):
public override void OnNavigatedTo(object navigationParameter, NavigationMode navigationMode,
Dictionary<string, object> viewModelState)
{
if (((App)Application.Current).MustPreventNavigationToPageNotToBeResumedOn)
{
// If must prevent navigation to this page (that should not be navigated to after
// suspension and termination) we reset the marker and just go back.
((App)Application.Current).MustPreventNavigationToPageNotToBeResumedOn = false;
this.navigationService.GoBack();
}
else
{
base.OnNavigatedTo(navigationParameter, navigationMode, viewModelState);
}
}

Related

Auto dismiss Login page when logged

I have the following page navigation in my app:
AnyPage -> Login -> Register
When the user gets registered he is automatically logged to. So I want the Login page to be closed automatically if the user go back to it and is logged.
I tried to add some code to the LoginPage.onNavigatedTo method but it doesn't work.
protected override void OnNavigatedTo(NavigationEventArgs e)
{
this.navigationHelper.OnNavigatedTo(e);
if(AccountController.isLogged()){
Frame.GoBack();
}
}
How can I do it?
The OnNavigatedTo and OnNavigatedFrom methods are part of the ongoing navigation operation. When you try to start a new navigation while there is one in progress, navigation methods will stop and return false.
Simple trick is: Make your OnNavigatedTo async and add a delay before navigating back.
protected override async void OnNavigatedTo(NavigationEventArgs e)
{
this.navigationHelper.OnNavigatedTo(e);
if(AccountController.isLogged()){
await Task.Delay(1);
Frame.GoBack();
}
}
The reason this works is: Navigation is handled on the UI Thread. As the Event Methods are void returning, they are not awaited and if you return a task inside of them, the current caller finishes his current task. Whatever comes after the await is queued to the Dispatcher and finished once he has time for it (which is immediately after the navigation operation finishes).

"Events type" in java

My program contain two classes, one represent the main program and the other one is a gui implemented using swing,
I'm trying to create an "event type", meaning I want my main program to wait until the UserInterface (GUI) will indicate some event, like pressing a button, and I would like to sends some information when my button is pressed.
General Code for the main program (this is the relevant section)
// Open window GUI with the requested BID and wait for confirmation or denial
HumanIFWindow nextWindowGUI = new HumanIFWindow();
nextWindowGUI.setVisible(true);
// ----------------- //
// - Wait on event - //
// ----------------- //
// Here is where I want to wait for the gui Indication
return returnedBid;
Code for the GUI (Again only relevant part)
JButton btnAprove = new JButton("Aprove");
btnAprove.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// ----------------- //
// - Trigger event - //
// ----------------- //
// Here is where I want to trigger the event
}});
Preferably I would like to use some library, is there's one that match my needs?
(Maybe BusEvent?)
Edit to specify the question (Thanks Kishan Sarsecha Gajjar)
I want the first class (the general one) to enter a wait statement, I know how to wait using:
while( someBoolean...)
Thread.sleep(...)
and I can change someBoolean with a handle in the GUI class, Like:
FisrtClass.someBoolean == False
But I want something nicer and neater, like a library that Implements the sleep statement. and there's no additional code needed. Is there something like that?
I've looked at Google-BusEvent library but I'm not sure if that's compatible
EDIT, adding JDialog
updated code: Main program:
Bid returnedBid = requestBid;
// Open window GUI with the requested BID and wait for confirmation
DialogHumanConfirmManual nextWindowGUI = new DialogHumanConfirmManual(requestBid);
// Wait on event
if ( (returnedBid = nextWindowGUI.getAnswer()) != null ){
System.out.println("Got Bid " + returnedBid.print());
}
GUI - Dialog:
public DialogHumanConfirmManual(Bid requestedBid){
currentBid = requestedBid;
currentBid.approvedHuman = false;
Dialog mainFrame = new Dialog(new Frame());
myPanel = new JPanel();
getContentPane().add(myPanel);
myPanel.add(new JLabel("Confirmation Dialog"));
yesButton = new JButton("Confirm");
yesButton.addActionListener(this);
myPanel.add(yesButton);
noButton = new JButton("No");
noButton.addActionListener(this);
myPanel.add(noButton);
pack();
setVisible(true);
}
public void actionPerformed(ActionEvent e) {
if (yesButton == e.getSource()) {
currentBid.approvedHuman = true;
answeredBid = currentBid;
}
}
After opening the Dialog the if ( returnBid ) is called, which result in Null Pointer Exception later on in the code, So How can I delay the main program until the user can Confirm the request??
the other one is a gui implemented using swing,
Use a modal JDialog not a JFrame.
Once the dialog is made visible, the code after the setVisible(true) statement will NOT execute until the dialog is closed.
Read the section from the Swing tutorial on How to Make Dialogs for more information. The tutorial covers the JOptionPane class, but you can just use a JDialog, which is created exactly the same way a JFrame is. You can choose whether to use a JOptionPane or JDialog depending on your exact requirement.

Metro App SuspensionManager Override SaveState Behaviour

How do I modify the SuspensionManager object in a Metro App, to SaveState for the MainPage only and discard State and Navigation for any child pages?
E.g. I have a MainPage that allows you to Navigate to a ChildPage. If the Metro App is Closed or Suspended, I want the ChildPage to override the MainPage state values.
Now, the next time the user opens the app, the MainPage should open and not the ChildPage. Also the MainPage should show State that the ChildPage updated before the app was Closed or Suspended.
Any ideas on how the SuspensionManager object can be safely modified to accomplish this?
Why not just add your data from the ChildPage to the SessionState dictionatry and fill it into the MainPage when the app resumes ?
You don't even need to modify the SuspensionManager for doing that!
public BasicPage1() {
this.InitializeComponent();
Application.Current.Suspending += Current_Suspending;
Application.Current.Resuming += Current_Resuming;
}
void Current_Resuming( object sender, object e ) {
var name = SuspensionManager.SessionState["name"].ToString();
}
void Current_Suspending( object sender, Windows.ApplicationModel.SuspendingEventArgs e ) {
SuspensionManager.SessionState.Add( "name", "danielovich" );
}
Using the suggestion from Danielovich (which is NOT complete), the solution is 2 parts:
Firstly:
No longer save state in the pageState object, instead save state
using the SessionState object. Why? This is so that all Pages can share the same State information.
Secondly:
To ensure, that NavigationState is not saved so that MainPage is always the default page, we need to change the SaveFrameNavigationState in SuspensionManager as follows:
private static void SaveFrameNavigationState(Frame frame)
{
var frameState = SessionStateForFrame(frame);
frame.GetNavigationState();
frameState["Navigation"] = "1,1,0,15,Skycap.MainPage,12,0";
}

Windows Store App launch

I'm having issues with my Windows Store App launch. When I use the "close app gesture" (slide the app from top to bottom) and then launch the app again very fast, sometimes a blank black screen appears and when I click on it, it, the Start menu appears, and a "MoAppHang" event is logged.
My App_Launched event code is here:
protected override async void OnLaunched(LaunchActivatedEventArgs args)
{
if (args.PreviousExecutionState == ApplicationExecutionState.Terminated )
{
// Restore the saved session state only when appropriate
await SuspensionManager.RestoreAsync();
}
// Do not repeat app initialization when already running, just ensure that
// the window is active
if (args.PreviousExecutionState == ApplicationExecutionState.Running)
{
if (!string.IsNullOrEmpty(args.Arguments))
{
Frame f = Window.Current.Content as Frame;
if (f != null)
{
UseSecondaryTileNavigation(f, args.Arguments);
}
}
Window.Current.Activate();
return;
}
Frame rootFrame;
if (Window.Current.Content == null)
{
// Create a Frame to act as the navigation context and associate it with
// a SuspensionManager key
rootFrame = new Frame();
SuspensionManager.RegisterFrame(rootFrame, "AppFrame");
}
else
{
rootFrame = (Frame)Window.Current.Content;
}
if (!await DatabaseHelper.ExistsDatabase())
{
await DatabaseHelper.CreateDatabase();
}
if (rootFrame.Content == null)
{
// When the navigation stack isn't restored navigate to the first page,
// configuring the new page by passing required information as a navigation
// parameter
if (!rootFrame.Navigate(typeof(ItemsPage), "AllGroups"))
{
throw new Exception("Failed to create initial page");
}
}
if (!string.IsNullOrEmpty(args.Arguments))
{
UseSecondaryTileNavigation(rootFrame, args.Arguments);
}
// Place the frame in the current Window and ensure that it is active
if (Window.Current.Content == null)
{
Window.Current.Content = rootFrame;
}
Window.Current.Activate();
The UseSecondaryTileNavigation performs navigation when user opens the app using secondary tile (it basically uses the Frame parameter and Navigates it to the correct location using Frame.Navigate).
Where am I going wrong?
Thank you all!
It looks like you could potentially be doing a bit of time-consuming work in your launch handler. The first suggestion I'd make is to use a custom splash screen technique. That is, in your OnLaunched handler try to set the Window.Current.Content and activate the window and get out of that method ASAP. You could set Window.Current.Content to a page that just shows a loading progress bar - and handle your actual loading logic in there.
The next thing to look at - is what happens when your app is launched while it is still suspending? (Do you have a suspending handler?) Can your app handle the case when it is (re-)launched before a previous suspension / close completes?
I've noticed that it generally seems to take a few seconds before the app is fully closed (even though you close it using the drag down gesture).

removing mouse events/controls from swing components with glasspane

I have a client-server application and i am using swing in the client side. My swing client has one main window (jframe) and lots of panels, toolbars and menubar in it.
I want to remove all client action/mouse events (or simply grab and do nothing) while client is waiting response from server by means of glasssPane.
Here is the code i wrote:
private final static MouseAdapter mouseAdapter = new MouseAdapter()
{
public void mouseClicked(MouseEvent e)
{
System.out.println("MouseClicked..!");
}
};
private static Cursor WAIT_CURSOR = Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR);
private static Cursor DEFAULT_CURSOR = Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR);
and
public static void startWaitCursor(JComponent comp)
{
MainWindow root = ((MainWindow) comp.getTopLevelAncestor());
root.getGlassPane().setCursor(WAIT_CURSOR);
root.getGlassPane().addMouseListener(mouseAdapter);
root.getGlassPane().setVisible(true);
}
public static void stopWaitCursor(JComponent comp)
{
MainWindow root = ((MainWindow) comp.getTopLevelAncestor());
root.getGlassPane().setCursor(DEFAULT_CURSOR);
root.getGlassPane().setVisible(false);
}
but i am not able to manage the grab mouse events. Changing cursors at the glassPane is working fine but either i am not able to add mouseAdapter or am not able to make glasssPane become to the top level component.
Any idea?
Thanks.
I realized that my code is working but my problem is threading related. My code was something like:
startWaitCursor();
work(); // server request that takes time
stopWaitCursor();
and changed it to:
startWaitCursor();
SwingUtilities.invokeLater(new Runnable() {
poblic void run() {
try
{
work(); // server request
}
finally
{
stopWaitCursor();
}
by doing this modification i could see the settings i made in the startWaitCursor() method while client is waiting response from the server.
But stil there is a small problem. In startWaitCursor() method i desabled key, mouse and focus events for the glass pane but events are still captured by main frame even glassPane is displayed.
addMouseListener(new MouseAdapter() {});
addMouseMotionListener(new MouseMotionAdapter() {});
addKeyListener(this);
setFocusTraversalKeysEnabled(false);
After server response reached to client and stopWaitCursor() method is invoked the events handled in the main frame.
If i disable the main frame of my application while client is waiting than cursor is not being changed to wait_cursor, if i am not disable the main frame then cursor is being changed but the events are queued.
cheers...
After digging swing threads issues couple of days, i finally found the real answer: SwingWorker
Now my final code is something like,
startWaitCursor();
SwingWorker worker = new SwingWorker() {
public Object doInBackground()
{
doWork(); // time consuming server request
return null;
}
public void done()
{
stopWaitCursor();
}
};
worker.execute();
In startWaitCursor() method i set the glasspane visible (with alpha valued background), display a message to warn the user time consuming job is doing, set the cursor to wait_cursor (hourglass) and consume all the key, mouse events. That is it.
And by using SwingWorker my client is actually responsive (it is working as if no server request is made) but since i display the glasspane and consume all key and mouse events it feels like irresponsive.
What a relief.. SwingWorker rocks...
cheers..