WP8: Fast app resume + secondary tile + MainPage = 2 instances

1.3k views Asked by At

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

There are 1 answers

6
Romasz On BEST ANSWER

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.