3

I'm having the same problem posed here:

http://social.msdn.microsoft.com/Forums/wpapps/en-us/af8615e7-8e90-4069-aa4d-3c4a84a6a3d0/windows-phone-8-fast-app-resume-with-deeplinks?forum=wpdevelop

I'm no C# or WP expert, so please bear with me.

  • I have secondary tiles which link to "/MainPage.xaml?id=XX".
  • I have fast app resume enabled. (ActivationPolicy="Resume" in the app manifest)
  • I only have one page in my app: MainPage.xaml.

Problem: When I resume the app using a secondary tile ("/MainPage.xaml?id=XX"), I get a brief view of the previous instance (that would have resumed) and then the MainPage initializes again, creating a new instance. In effect, the app is loading from scratch after giving me a peek of what was previously open.

That is obviously undesired behavior. I want to use the existing instance to perform my task.


Attempt 1: Use e.Cancel = true; to cancel the navigation to the MainPage.xaml:
(using the App.xaml.cs code from the official Fast App Resume sample to identify how the app was launched)

...
else if (e.NavigationMode == NavigationMode.New && wasRelaunched)
{
  // This block will run if the previous navigation was a relaunch
  wasRelaunched = false;

  if (e.Uri.ToString().Contains("="))
  {
    // This block will run if the launch Uri contains "=" (ex: "id=XX") which
    // was specified when the secondary tile was created in MainPage.xaml.cs
    sessionType = SessionType.DeepLink;

    e.Cancel = true; // <======================== Here

    // The app was relaunched via a Deep Link.
    // The page stack will be cleared.
  }
}
...

Problem: In doing so, my OnNavigatedTo event handlers never fire, so my query string is never parsed.

protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
  String navId;
  if (e.NavigationMode != System.Windows.Navigation.NavigationMode.Back)
  {
    if (NavigationContext.QueryString.TryGetValue("id", out navId))
    {
      MessageBox.Show(navId.ToString()); // Not reached
    }
  }
  ...

Attempt 2: Use e.Cancel = true; to cancel the navigation to the MainPage.xaml, AND pass the Uri to a method in MainPage:

// App.xaml.cs
...
else if (e.NavigationMode == NavigationMode.New && wasRelaunched)
{
  // This block will run if the previous navigation was a relaunch
  wasRelaunched = false;

  if (e.Uri.ToString().Contains("="))
  {
    // This block will run if the launch Uri contains "=" (ex: "id=XX") which
    // was specified when the secondary tile was created in MainPage.xaml.cs
    sessionType = SessionType.DeepLink;

    e.Cancel = true;

    MainPage.GoToDeepLink(e.Uri); // <======================== Here

    // The app was relaunched via a Deep Link.
    // The page stack will be cleared.
  }
}
...

// MainPage.xaml.cs
public static void GoToDeepLink(Uri uri) // <======================== Here
{
  // Convert the uri into a list and navigate to it.
  string path = uri.ToString();
  string id = path.Substring(path.LastIndexOf('=') + 1);

  MyList list = App.ViewModel.ListFromId(Convert.ToInt32(id));
  pivotLists.SelectedItem = list;
}

Problem: I get an error that pivotLists is non-static and thus requires an object reference. I think that in order to get this to work I'd need to create a new instance of MainPage (MainPage newMainPage = new MainPage();) and call newMainPage.pivotLists.SelectedItem = list; -- BUT I don't know how to use newMainPage instead of the existing one/replace it... or if that's something I want/won't cause further problems/complications.


I don't know what the solution is to this problem, and I may be going in the completely wrong direction. Please keep all suggestions in simple terms with code examples if you can, I'm still learning.

Thanks for any help.

1 Answers1

0

It seems that when you reopen your App from secondary tile, then it's reactivated and new instance of MainPage is created (even if there is one from previous run). If I understood you correctly, I've managed to do such a thing:

In app.xaml.cs:

I've added a variable which indicates if I should return to previous MainPage after Navigating from secondary tile - it needs to be static as I want to have access to it from MainPage

public static bool returnPage = false;

In RootFrame_Navigating I'm setting this variable to true in:

// ...
else if (e.NavigationMode == NavigationMode.New && wasRelaunched)
{
   // This block will run if the previous navigation was a relaunch
   wasRelaunched = false;
   returnPage = true;
// ...

In ClearBackStackAfterReset - prevent from deleting the old Page, when returning:

// ...
if (e.NavigationMode != NavigationMode.New || returnPage)
      return;
// ...

In MainPage.cs:

I've changed a little constructor, as I don't want to see a blink of a new Page:

public MainPage()
{
  if (!App.returnPage)
     InitializeComponent();
}

In MainPage I've also variable which is passed from secondary tile - it's also static, as I need only one instance of it:

private static string navId = "";

And the core of the trick - OnNavigatedTo:

protected override void OnNavigatedTo(NavigationEventArgs e)
{
  if (App.returnPage)
  {
     App.returnPage = false;
     NavigationContext.QueryString.TryGetValue("id", out navId);
     NavigationService.GoBack();
  }
  else if (e.NavigationMode != NavigationMode.Reset)
  {
     // normal navigation
  }
}

It works like this:

  • when you launch normally your App, returnPage is false, everything goes normal
  • when you activate it from secondary tile few things happen:

    1. first goes navigation to your previous page with NavigationMode.Reset - we are not interested in it, so I switched it off - nothing should happen
    2. then program tries to create new instance of MainPage, but returnPage is true, and because of the if statement, InitializeComponent won't run. Just after this, in OnNavigatedTo, program saves passed querystring and Navigates Back to previous instance of MainPage - from previous run
    3. at last we are navigating to right MainPage with NavigationMode.Back and we have our querystring saved in static variable.

You must be aware of two things: first - probably it can be little rebuild (I'm not sure if wasRelaunched is needed and so on) - you need to debug it and see of what you can get rid off. Second - you will probably need to test your App with Tombstone case.

Hope this helps.

Romasz
  • 29,662
  • 13
  • 79
  • 154
  • Thanks for the response. Unfortunately, when the app isn't initialized, it doesn't seem to reach `OnNavigatedTo` -- so, `NavigationService.GoBack();` is never called, and I get null errors (a black screen). I can't get it to resume without `InitializeComponent`. –  Feb 08 '14 at 21:01
  • @user2616836 Before I've written this answer, I've tested it on example. I haven't enocuntered such problems. Can you test it - http://sdrv.ms/1bALkuO ? – Romasz Feb 09 '14 at 07:24
  • 1
    Ahh, I needed to update `// Only clear the stack for 'new' (forward) and 'refresh' navigations if (e.NavigationMode != NavigationMode.New || returnPage)` –  Feb 09 '14 at 19:45
  • @user2616836 You are right, I've forgotten to mention about it ;) I'm editting now. – Romasz Feb 09 '14 at 19:49
  • 1
    [cont'd]...you should add that to your answer for anyone who stumbles on this. My main problem, though, still exists: the page fades out then fades back in. I realized it's due to the Telerik page transition I'm using. Even if I use the default RootFrame, it still "jumps" quickly sometimes during the GoBack. Unfortunate. But it works. Also, I changed the GoBack to check first, `if (NavigationService.CanGoBack) NavigationService.GoBack();`. This might be the best it can be. Thank you for the help! –  Feb 09 '14 at 19:51
  • @user2616836 You are welcome. For now it's the best what I was able to figure out. Happy coding and good luck! – Romasz Feb 09 '14 at 19:59