📜 ⬆️ ⬇️

Create an application for Windows Phone 7 from start to finish. Part 13. Application recovery after decontamination

Previous part

When a user leaves your application, it is deactivated. If the user uses the “Back” button to return to your application, you need to restore the application to the appropriate state.

In this part you will learn:

Tombstoning review


Your application can be interrupted and deactivated at any time, as a rule, this happens when the user switches to another application using the “Start” button. When this happens, your application should maintain its state so that it can be restored in the event of a return to it. However, isolated storage is too slow for short-term storage of state data. Instead, you cache data using in-memory dictionaries to quickly save and load data.
')
When an application is deactivated, its process can be stopped using a procedure called tombstoning (tombstone), which will save the application's records in memory and associate them with your cached state data. If the user goes back to your application, the operating system restarts the application process and sends back status data to it.

Tip:
When the application is interrupted and then resumed, users expect to continue working from the place where it was interrupted. For this reason, you should always implement tombstoning support for any page that can change its state. This refers to state changes as complex as updating user input, or as simple as changing the current selection in the list. Lack of tombstoning support can lead to poor usability at best and completely unexpected behavior at worst.

Certification Requirement:
Your application should not delay or prevent the user from making a call, answering an incoming call, or ending a call.

Tombstoning support implementation


In order to use a temporary cache that persists during tombstoning, follow these steps:
These two State properties are dictionaries in which you can store value / key type pairs, where values ​​can be primitive type values ​​or serializable objects. Please note that there is no guarantee that a deactivated application will ever be reactivated, so you should not use these dictionaries to store any application or user data that should be stored. For long-term storage, use isolated storage.

Performance Improvement Tip:
Use state dictionaries to restore state. Avoid recovering from isolated storage or from the Internet.

The Fuel Tracker application saves temporary page level states during the tombstoning process, but does not have application level state data to save. Each page saves state data with its PhoneApplicationPage.State property. For example, the FillupPage class contains a Fillup object bound to some text fields. This object is stored for long-term storage only when the user clicks the "Save" button. However, during tombstoning, the page places an object in the State dictionary of the page along with a value indicating whether the user made changes to it, as shown in the following code snippet. (The implementation of the Save button will be described in the Validation of Input Data section.)
private const string CURRENT_FILLUP_KEY = "CurrentFillup" ; private const string HAS_UNSAVED_CHANGES_KEY = "HasUnsavedChanges" ; private Fillup currentFillup; private bool hasUnsavedChanges; protected override void OnNavigatedFrom(NavigationEventArgs e) { base .OnNavigatedFrom(e); if (cacheChanges) { CommitTextBoxes(); this .State[CURRENT_FILLUP_KEY] = currentFillup; this .State[HAS_UNSAVED_CHANGES_KEY] = hasUnsavedChanges; } } protected override void OnNavigatedTo(NavigationEventArgs e) { base .OnNavigatedTo(e); CarHeader.DataContext = CarDataStore.Car; DataContext = currentFillup = State.ContainsKey(CURRENT_FILLUP_KEY) ? (Fillup) this .State[CURRENT_FILLUP_KEY] : new Fillup() { Date = DateTime .Now }; hasUnsavedChanges = State.ContainsKey(HAS_UNSAVED_CHANGES_KEY) ? ( bool )State[HAS_UNSAVED_CHANGES_KEY] : false ; } * This source code was highlighted with Source Code Highlighter .
  1. private const string CURRENT_FILLUP_KEY = "CurrentFillup" ; private const string HAS_UNSAVED_CHANGES_KEY = "HasUnsavedChanges" ; private Fillup currentFillup; private bool hasUnsavedChanges; protected override void OnNavigatedFrom(NavigationEventArgs e) { base .OnNavigatedFrom(e); if (cacheChanges) { CommitTextBoxes(); this .State[CURRENT_FILLUP_KEY] = currentFillup; this .State[HAS_UNSAVED_CHANGES_KEY] = hasUnsavedChanges; } } protected override void OnNavigatedTo(NavigationEventArgs e) { base .OnNavigatedTo(e); CarHeader.DataContext = CarDataStore.Car; DataContext = currentFillup = State.ContainsKey(CURRENT_FILLUP_KEY) ? (Fillup) this .State[CURRENT_FILLUP_KEY] : new Fillup() { Date = DateTime .Now }; hasUnsavedChanges = State.ContainsKey(HAS_UNSAVED_CHANGES_KEY) ? ( bool )State[HAS_UNSAVED_CHANGES_KEY] : false ; } * This source code was highlighted with Source Code Highlighter .
  2. private const string CURRENT_FILLUP_KEY = "CurrentFillup" ; private const string HAS_UNSAVED_CHANGES_KEY = "HasUnsavedChanges" ; private Fillup currentFillup; private bool hasUnsavedChanges; protected override void OnNavigatedFrom(NavigationEventArgs e) { base .OnNavigatedFrom(e); if (cacheChanges) { CommitTextBoxes(); this .State[CURRENT_FILLUP_KEY] = currentFillup; this .State[HAS_UNSAVED_CHANGES_KEY] = hasUnsavedChanges; } } protected override void OnNavigatedTo(NavigationEventArgs e) { base .OnNavigatedTo(e); CarHeader.DataContext = CarDataStore.Car; DataContext = currentFillup = State.ContainsKey(CURRENT_FILLUP_KEY) ? (Fillup) this .State[CURRENT_FILLUP_KEY] : new Fillup() { Date = DateTime .Now }; hasUnsavedChanges = State.ContainsKey(HAS_UNSAVED_CHANGES_KEY) ? ( bool )State[HAS_UNSAVED_CHANGES_KEY] : false ; } * This source code was highlighted with Source Code Highlighter .
  3. private const string CURRENT_FILLUP_KEY = "CurrentFillup" ; private const string HAS_UNSAVED_CHANGES_KEY = "HasUnsavedChanges" ; private Fillup currentFillup; private bool hasUnsavedChanges; protected override void OnNavigatedFrom(NavigationEventArgs e) { base .OnNavigatedFrom(e); if (cacheChanges) { CommitTextBoxes(); this .State[CURRENT_FILLUP_KEY] = currentFillup; this .State[HAS_UNSAVED_CHANGES_KEY] = hasUnsavedChanges; } } protected override void OnNavigatedTo(NavigationEventArgs e) { base .OnNavigatedTo(e); CarHeader.DataContext = CarDataStore.Car; DataContext = currentFillup = State.ContainsKey(CURRENT_FILLUP_KEY) ? (Fillup) this .State[CURRENT_FILLUP_KEY] : new Fillup() { Date = DateTime .Now }; hasUnsavedChanges = State.ContainsKey(HAS_UNSAVED_CHANGES_KEY) ? ( bool )State[HAS_UNSAVED_CHANGES_KEY] : false ; } * This source code was highlighted with Source Code Highlighter .
  4. private const string CURRENT_FILLUP_KEY = "CurrentFillup" ; private const string HAS_UNSAVED_CHANGES_KEY = "HasUnsavedChanges" ; private Fillup currentFillup; private bool hasUnsavedChanges; protected override void OnNavigatedFrom(NavigationEventArgs e) { base .OnNavigatedFrom(e); if (cacheChanges) { CommitTextBoxes(); this .State[CURRENT_FILLUP_KEY] = currentFillup; this .State[HAS_UNSAVED_CHANGES_KEY] = hasUnsavedChanges; } } protected override void OnNavigatedTo(NavigationEventArgs e) { base .OnNavigatedTo(e); CarHeader.DataContext = CarDataStore.Car; DataContext = currentFillup = State.ContainsKey(CURRENT_FILLUP_KEY) ? (Fillup) this .State[CURRENT_FILLUP_KEY] : new Fillup() { Date = DateTime .Now }; hasUnsavedChanges = State.ContainsKey(HAS_UNSAVED_CHANGES_KEY) ? ( bool )State[HAS_UNSAVED_CHANGES_KEY] : false ; } * This source code was highlighted with Source Code Highlighter .
  5. private const string CURRENT_FILLUP_KEY = "CurrentFillup" ; private const string HAS_UNSAVED_CHANGES_KEY = "HasUnsavedChanges" ; private Fillup currentFillup; private bool hasUnsavedChanges; protected override void OnNavigatedFrom(NavigationEventArgs e) { base .OnNavigatedFrom(e); if (cacheChanges) { CommitTextBoxes(); this .State[CURRENT_FILLUP_KEY] = currentFillup; this .State[HAS_UNSAVED_CHANGES_KEY] = hasUnsavedChanges; } } protected override void OnNavigatedTo(NavigationEventArgs e) { base .OnNavigatedTo(e); CarHeader.DataContext = CarDataStore.Car; DataContext = currentFillup = State.ContainsKey(CURRENT_FILLUP_KEY) ? (Fillup) this .State[CURRENT_FILLUP_KEY] : new Fillup() { Date = DateTime .Now }; hasUnsavedChanges = State.ContainsKey(HAS_UNSAVED_CHANGES_KEY) ? ( bool )State[HAS_UNSAVED_CHANGES_KEY] : false ; } * This source code was highlighted with Source Code Highlighter .
  6. private const string CURRENT_FILLUP_KEY = "CurrentFillup" ; private const string HAS_UNSAVED_CHANGES_KEY = "HasUnsavedChanges" ; private Fillup currentFillup; private bool hasUnsavedChanges; protected override void OnNavigatedFrom(NavigationEventArgs e) { base .OnNavigatedFrom(e); if (cacheChanges) { CommitTextBoxes(); this .State[CURRENT_FILLUP_KEY] = currentFillup; this .State[HAS_UNSAVED_CHANGES_KEY] = hasUnsavedChanges; } } protected override void OnNavigatedTo(NavigationEventArgs e) { base .OnNavigatedTo(e); CarHeader.DataContext = CarDataStore.Car; DataContext = currentFillup = State.ContainsKey(CURRENT_FILLUP_KEY) ? (Fillup) this .State[CURRENT_FILLUP_KEY] : new Fillup() { Date = DateTime .Now }; hasUnsavedChanges = State.ContainsKey(HAS_UNSAVED_CHANGES_KEY) ? ( bool )State[HAS_UNSAVED_CHANGES_KEY] : false ; } * This source code was highlighted with Source Code Highlighter .
  7. private const string CURRENT_FILLUP_KEY = "CurrentFillup" ; private const string HAS_UNSAVED_CHANGES_KEY = "HasUnsavedChanges" ; private Fillup currentFillup; private bool hasUnsavedChanges; protected override void OnNavigatedFrom(NavigationEventArgs e) { base .OnNavigatedFrom(e); if (cacheChanges) { CommitTextBoxes(); this .State[CURRENT_FILLUP_KEY] = currentFillup; this .State[HAS_UNSAVED_CHANGES_KEY] = hasUnsavedChanges; } } protected override void OnNavigatedTo(NavigationEventArgs e) { base .OnNavigatedTo(e); CarHeader.DataContext = CarDataStore.Car; DataContext = currentFillup = State.ContainsKey(CURRENT_FILLUP_KEY) ? (Fillup) this .State[CURRENT_FILLUP_KEY] : new Fillup() { Date = DateTime .Now }; hasUnsavedChanges = State.ContainsKey(HAS_UNSAVED_CHANGES_KEY) ? ( bool )State[HAS_UNSAVED_CHANGES_KEY] : false ; } * This source code was highlighted with Source Code Highlighter .
  8. private const string CURRENT_FILLUP_KEY = "CurrentFillup" ; private const string HAS_UNSAVED_CHANGES_KEY = "HasUnsavedChanges" ; private Fillup currentFillup; private bool hasUnsavedChanges; protected override void OnNavigatedFrom(NavigationEventArgs e) { base .OnNavigatedFrom(e); if (cacheChanges) { CommitTextBoxes(); this .State[CURRENT_FILLUP_KEY] = currentFillup; this .State[HAS_UNSAVED_CHANGES_KEY] = hasUnsavedChanges; } } protected override void OnNavigatedTo(NavigationEventArgs e) { base .OnNavigatedTo(e); CarHeader.DataContext = CarDataStore.Car; DataContext = currentFillup = State.ContainsKey(CURRENT_FILLUP_KEY) ? (Fillup) this .State[CURRENT_FILLUP_KEY] : new Fillup() { Date = DateTime .Now }; hasUnsavedChanges = State.ContainsKey(HAS_UNSAVED_CHANGES_KEY) ? ( bool )State[HAS_UNSAVED_CHANGES_KEY] : false ; } * This source code was highlighted with Source Code Highlighter .
  9. private const string CURRENT_FILLUP_KEY = "CurrentFillup" ; private const string HAS_UNSAVED_CHANGES_KEY = "HasUnsavedChanges" ; private Fillup currentFillup; private bool hasUnsavedChanges; protected override void OnNavigatedFrom(NavigationEventArgs e) { base .OnNavigatedFrom(e); if (cacheChanges) { CommitTextBoxes(); this .State[CURRENT_FILLUP_KEY] = currentFillup; this .State[HAS_UNSAVED_CHANGES_KEY] = hasUnsavedChanges; } } protected override void OnNavigatedTo(NavigationEventArgs e) { base .OnNavigatedTo(e); CarHeader.DataContext = CarDataStore.Car; DataContext = currentFillup = State.ContainsKey(CURRENT_FILLUP_KEY) ? (Fillup) this .State[CURRENT_FILLUP_KEY] : new Fillup() { Date = DateTime .Now }; hasUnsavedChanges = State.ContainsKey(HAS_UNSAVED_CHANGES_KEY) ? ( bool )State[HAS_UNSAVED_CHANGES_KEY] : false ; } * This source code was highlighted with Source Code Highlighter .
  10. private const string CURRENT_FILLUP_KEY = "CurrentFillup" ; private const string HAS_UNSAVED_CHANGES_KEY = "HasUnsavedChanges" ; private Fillup currentFillup; private bool hasUnsavedChanges; protected override void OnNavigatedFrom(NavigationEventArgs e) { base .OnNavigatedFrom(e); if (cacheChanges) { CommitTextBoxes(); this .State[CURRENT_FILLUP_KEY] = currentFillup; this .State[HAS_UNSAVED_CHANGES_KEY] = hasUnsavedChanges; } } protected override void OnNavigatedTo(NavigationEventArgs e) { base .OnNavigatedTo(e); CarHeader.DataContext = CarDataStore.Car; DataContext = currentFillup = State.ContainsKey(CURRENT_FILLUP_KEY) ? (Fillup) this .State[CURRENT_FILLUP_KEY] : new Fillup() { Date = DateTime .Now }; hasUnsavedChanges = State.ContainsKey(HAS_UNSAVED_CHANGES_KEY) ? ( bool )State[HAS_UNSAVED_CHANGES_KEY] : false ; } * This source code was highlighted with Source Code Highlighter .
  11. private const string CURRENT_FILLUP_KEY = "CurrentFillup" ; private const string HAS_UNSAVED_CHANGES_KEY = "HasUnsavedChanges" ; private Fillup currentFillup; private bool hasUnsavedChanges; protected override void OnNavigatedFrom(NavigationEventArgs e) { base .OnNavigatedFrom(e); if (cacheChanges) { CommitTextBoxes(); this .State[CURRENT_FILLUP_KEY] = currentFillup; this .State[HAS_UNSAVED_CHANGES_KEY] = hasUnsavedChanges; } } protected override void OnNavigatedTo(NavigationEventArgs e) { base .OnNavigatedTo(e); CarHeader.DataContext = CarDataStore.Car; DataContext = currentFillup = State.ContainsKey(CURRENT_FILLUP_KEY) ? (Fillup) this .State[CURRENT_FILLUP_KEY] : new Fillup() { Date = DateTime .Now }; hasUnsavedChanges = State.ContainsKey(HAS_UNSAVED_CHANGES_KEY) ? ( bool )State[HAS_UNSAVED_CHANGES_KEY] : false ; } * This source code was highlighted with Source Code Highlighter .
  12. private const string CURRENT_FILLUP_KEY = "CurrentFillup" ; private const string HAS_UNSAVED_CHANGES_KEY = "HasUnsavedChanges" ; private Fillup currentFillup; private bool hasUnsavedChanges; protected override void OnNavigatedFrom(NavigationEventArgs e) { base .OnNavigatedFrom(e); if (cacheChanges) { CommitTextBoxes(); this .State[CURRENT_FILLUP_KEY] = currentFillup; this .State[HAS_UNSAVED_CHANGES_KEY] = hasUnsavedChanges; } } protected override void OnNavigatedTo(NavigationEventArgs e) { base .OnNavigatedTo(e); CarHeader.DataContext = CarDataStore.Car; DataContext = currentFillup = State.ContainsKey(CURRENT_FILLUP_KEY) ? (Fillup) this .State[CURRENT_FILLUP_KEY] : new Fillup() { Date = DateTime .Now }; hasUnsavedChanges = State.ContainsKey(HAS_UNSAVED_CHANGES_KEY) ? ( bool )State[HAS_UNSAVED_CHANGES_KEY] : false ; } * This source code was highlighted with Source Code Highlighter .
  13. private const string CURRENT_FILLUP_KEY = "CurrentFillup" ; private const string HAS_UNSAVED_CHANGES_KEY = "HasUnsavedChanges" ; private Fillup currentFillup; private bool hasUnsavedChanges; protected override void OnNavigatedFrom(NavigationEventArgs e) { base .OnNavigatedFrom(e); if (cacheChanges) { CommitTextBoxes(); this .State[CURRENT_FILLUP_KEY] = currentFillup; this .State[HAS_UNSAVED_CHANGES_KEY] = hasUnsavedChanges; } } protected override void OnNavigatedTo(NavigationEventArgs e) { base .OnNavigatedTo(e); CarHeader.DataContext = CarDataStore.Car; DataContext = currentFillup = State.ContainsKey(CURRENT_FILLUP_KEY) ? (Fillup) this .State[CURRENT_FILLUP_KEY] : new Fillup() { Date = DateTime .Now }; hasUnsavedChanges = State.ContainsKey(HAS_UNSAVED_CHANGES_KEY) ? ( bool )State[HAS_UNSAVED_CHANGES_KEY] : false ; } * This source code was highlighted with Source Code Highlighter .
  14. private const string CURRENT_FILLUP_KEY = "CurrentFillup" ; private const string HAS_UNSAVED_CHANGES_KEY = "HasUnsavedChanges" ; private Fillup currentFillup; private bool hasUnsavedChanges; protected override void OnNavigatedFrom(NavigationEventArgs e) { base .OnNavigatedFrom(e); if (cacheChanges) { CommitTextBoxes(); this .State[CURRENT_FILLUP_KEY] = currentFillup; this .State[HAS_UNSAVED_CHANGES_KEY] = hasUnsavedChanges; } } protected override void OnNavigatedTo(NavigationEventArgs e) { base .OnNavigatedTo(e); CarHeader.DataContext = CarDataStore.Car; DataContext = currentFillup = State.ContainsKey(CURRENT_FILLUP_KEY) ? (Fillup) this .State[CURRENT_FILLUP_KEY] : new Fillup() { Date = DateTime .Now }; hasUnsavedChanges = State.ContainsKey(HAS_UNSAVED_CHANGES_KEY) ? ( bool )State[HAS_UNSAVED_CHANGES_KEY] : false ; } * This source code was highlighted with Source Code Highlighter .
  15. private const string CURRENT_FILLUP_KEY = "CurrentFillup" ; private const string HAS_UNSAVED_CHANGES_KEY = "HasUnsavedChanges" ; private Fillup currentFillup; private bool hasUnsavedChanges; protected override void OnNavigatedFrom(NavigationEventArgs e) { base .OnNavigatedFrom(e); if (cacheChanges) { CommitTextBoxes(); this .State[CURRENT_FILLUP_KEY] = currentFillup; this .State[HAS_UNSAVED_CHANGES_KEY] = hasUnsavedChanges; } } protected override void OnNavigatedTo(NavigationEventArgs e) { base .OnNavigatedTo(e); CarHeader.DataContext = CarDataStore.Car; DataContext = currentFillup = State.ContainsKey(CURRENT_FILLUP_KEY) ? (Fillup) this .State[CURRENT_FILLUP_KEY] : new Fillup() { Date = DateTime .Now }; hasUnsavedChanges = State.ContainsKey(HAS_UNSAVED_CHANGES_KEY) ? ( bool )State[HAS_UNSAVED_CHANGES_KEY] : false ; } * This source code was highlighted with Source Code Highlighter .
  16. private const string CURRENT_FILLUP_KEY = "CurrentFillup" ; private const string HAS_UNSAVED_CHANGES_KEY = "HasUnsavedChanges" ; private Fillup currentFillup; private bool hasUnsavedChanges; protected override void OnNavigatedFrom(NavigationEventArgs e) { base .OnNavigatedFrom(e); if (cacheChanges) { CommitTextBoxes(); this .State[CURRENT_FILLUP_KEY] = currentFillup; this .State[HAS_UNSAVED_CHANGES_KEY] = hasUnsavedChanges; } } protected override void OnNavigatedTo(NavigationEventArgs e) { base .OnNavigatedTo(e); CarHeader.DataContext = CarDataStore.Car; DataContext = currentFillup = State.ContainsKey(CURRENT_FILLUP_KEY) ? (Fillup) this .State[CURRENT_FILLUP_KEY] : new Fillup() { Date = DateTime .Now }; hasUnsavedChanges = State.ContainsKey(HAS_UNSAVED_CHANGES_KEY) ? ( bool )State[HAS_UNSAVED_CHANGES_KEY] : false ; } * This source code was highlighted with Source Code Highlighter .
  17. private const string CURRENT_FILLUP_KEY = "CurrentFillup" ; private const string HAS_UNSAVED_CHANGES_KEY = "HasUnsavedChanges" ; private Fillup currentFillup; private bool hasUnsavedChanges; protected override void OnNavigatedFrom(NavigationEventArgs e) { base .OnNavigatedFrom(e); if (cacheChanges) { CommitTextBoxes(); this .State[CURRENT_FILLUP_KEY] = currentFillup; this .State[HAS_UNSAVED_CHANGES_KEY] = hasUnsavedChanges; } } protected override void OnNavigatedTo(NavigationEventArgs e) { base .OnNavigatedTo(e); CarHeader.DataContext = CarDataStore.Car; DataContext = currentFillup = State.ContainsKey(CURRENT_FILLUP_KEY) ? (Fillup) this .State[CURRENT_FILLUP_KEY] : new Fillup() { Date = DateTime .Now }; hasUnsavedChanges = State.ContainsKey(HAS_UNSAVED_CHANGES_KEY) ? ( bool )State[HAS_UNSAVED_CHANGES_KEY] : false ; } * This source code was highlighted with Source Code Highlighter .
  18. private const string CURRENT_FILLUP_KEY = "CurrentFillup" ; private const string HAS_UNSAVED_CHANGES_KEY = "HasUnsavedChanges" ; private Fillup currentFillup; private bool hasUnsavedChanges; protected override void OnNavigatedFrom(NavigationEventArgs e) { base .OnNavigatedFrom(e); if (cacheChanges) { CommitTextBoxes(); this .State[CURRENT_FILLUP_KEY] = currentFillup; this .State[HAS_UNSAVED_CHANGES_KEY] = hasUnsavedChanges; } } protected override void OnNavigatedTo(NavigationEventArgs e) { base .OnNavigatedTo(e); CarHeader.DataContext = CarDataStore.Car; DataContext = currentFillup = State.ContainsKey(CURRENT_FILLUP_KEY) ? (Fillup) this .State[CURRENT_FILLUP_KEY] : new Fillup() { Date = DateTime .Now }; hasUnsavedChanges = State.ContainsKey(HAS_UNSAVED_CHANGES_KEY) ? ( bool )State[HAS_UNSAVED_CHANGES_KEY] : false ; } * This source code was highlighted with Source Code Highlighter .
  19. private const string CURRENT_FILLUP_KEY = "CurrentFillup" ; private const string HAS_UNSAVED_CHANGES_KEY = "HasUnsavedChanges" ; private Fillup currentFillup; private bool hasUnsavedChanges; protected override void OnNavigatedFrom(NavigationEventArgs e) { base .OnNavigatedFrom(e); if (cacheChanges) { CommitTextBoxes(); this .State[CURRENT_FILLUP_KEY] = currentFillup; this .State[HAS_UNSAVED_CHANGES_KEY] = hasUnsavedChanges; } } protected override void OnNavigatedTo(NavigationEventArgs e) { base .OnNavigatedTo(e); CarHeader.DataContext = CarDataStore.Car; DataContext = currentFillup = State.ContainsKey(CURRENT_FILLUP_KEY) ? (Fillup) this .State[CURRENT_FILLUP_KEY] : new Fillup() { Date = DateTime .Now }; hasUnsavedChanges = State.ContainsKey(HAS_UNSAVED_CHANGES_KEY) ? ( bool )State[HAS_UNSAVED_CHANGES_KEY] : false ; } * This source code was highlighted with Source Code Highlighter .
  20. private const string CURRENT_FILLUP_KEY = "CurrentFillup" ; private const string HAS_UNSAVED_CHANGES_KEY = "HasUnsavedChanges" ; private Fillup currentFillup; private bool hasUnsavedChanges; protected override void OnNavigatedFrom(NavigationEventArgs e) { base .OnNavigatedFrom(e); if (cacheChanges) { CommitTextBoxes(); this .State[CURRENT_FILLUP_KEY] = currentFillup; this .State[HAS_UNSAVED_CHANGES_KEY] = hasUnsavedChanges; } } protected override void OnNavigatedTo(NavigationEventArgs e) { base .OnNavigatedTo(e); CarHeader.DataContext = CarDataStore.Car; DataContext = currentFillup = State.ContainsKey(CURRENT_FILLUP_KEY) ? (Fillup) this .State[CURRENT_FILLUP_KEY] : new Fillup() { Date = DateTime .Now }; hasUnsavedChanges = State.ContainsKey(HAS_UNSAVED_CHANGES_KEY) ? ( bool )State[HAS_UNSAVED_CHANGES_KEY] : false ; } * This source code was highlighted with Source Code Highlighter .
  21. private const string CURRENT_FILLUP_KEY = "CurrentFillup" ; private const string HAS_UNSAVED_CHANGES_KEY = "HasUnsavedChanges" ; private Fillup currentFillup; private bool hasUnsavedChanges; protected override void OnNavigatedFrom(NavigationEventArgs e) { base .OnNavigatedFrom(e); if (cacheChanges) { CommitTextBoxes(); this .State[CURRENT_FILLUP_KEY] = currentFillup; this .State[HAS_UNSAVED_CHANGES_KEY] = hasUnsavedChanges; } } protected override void OnNavigatedTo(NavigationEventArgs e) { base .OnNavigatedTo(e); CarHeader.DataContext = CarDataStore.Car; DataContext = currentFillup = State.ContainsKey(CURRENT_FILLUP_KEY) ? (Fillup) this .State[CURRENT_FILLUP_KEY] : new Fillup() { Date = DateTime .Now }; hasUnsavedChanges = State.ContainsKey(HAS_UNSAVED_CHANGES_KEY) ? ( bool )State[HAS_UNSAVED_CHANGES_KEY] : false ; } * This source code was highlighted with Source Code Highlighter .
  22. private const string CURRENT_FILLUP_KEY = "CurrentFillup" ; private const string HAS_UNSAVED_CHANGES_KEY = "HasUnsavedChanges" ; private Fillup currentFillup; private bool hasUnsavedChanges; protected override void OnNavigatedFrom(NavigationEventArgs e) { base .OnNavigatedFrom(e); if (cacheChanges) { CommitTextBoxes(); this .State[CURRENT_FILLUP_KEY] = currentFillup; this .State[HAS_UNSAVED_CHANGES_KEY] = hasUnsavedChanges; } } protected override void OnNavigatedTo(NavigationEventArgs e) { base .OnNavigatedTo(e); CarHeader.DataContext = CarDataStore.Car; DataContext = currentFillup = State.ContainsKey(CURRENT_FILLUP_KEY) ? (Fillup) this .State[CURRENT_FILLUP_KEY] : new Fillup() { Date = DateTime .Now }; hasUnsavedChanges = State.ContainsKey(HAS_UNSAVED_CHANGES_KEY) ? ( bool )State[HAS_UNSAVED_CHANGES_KEY] : false ; } * This source code was highlighted with Source Code Highlighter .
  23. private const string CURRENT_FILLUP_KEY = "CurrentFillup" ; private const string HAS_UNSAVED_CHANGES_KEY = "HasUnsavedChanges" ; private Fillup currentFillup; private bool hasUnsavedChanges; protected override void OnNavigatedFrom(NavigationEventArgs e) { base .OnNavigatedFrom(e); if (cacheChanges) { CommitTextBoxes(); this .State[CURRENT_FILLUP_KEY] = currentFillup; this .State[HAS_UNSAVED_CHANGES_KEY] = hasUnsavedChanges; } } protected override void OnNavigatedTo(NavigationEventArgs e) { base .OnNavigatedTo(e); CarHeader.DataContext = CarDataStore.Car; DataContext = currentFillup = State.ContainsKey(CURRENT_FILLUP_KEY) ? (Fillup) this .State[CURRENT_FILLUP_KEY] : new Fillup() { Date = DateTime .Now }; hasUnsavedChanges = State.ContainsKey(HAS_UNSAVED_CHANGES_KEY) ? ( bool )State[HAS_UNSAVED_CHANGES_KEY] : false ; } * This source code was highlighted with Source Code Highlighter .
  24. private const string CURRENT_FILLUP_KEY = "CurrentFillup" ; private const string HAS_UNSAVED_CHANGES_KEY = "HasUnsavedChanges" ; private Fillup currentFillup; private bool hasUnsavedChanges; protected override void OnNavigatedFrom(NavigationEventArgs e) { base .OnNavigatedFrom(e); if (cacheChanges) { CommitTextBoxes(); this .State[CURRENT_FILLUP_KEY] = currentFillup; this .State[HAS_UNSAVED_CHANGES_KEY] = hasUnsavedChanges; } } protected override void OnNavigatedTo(NavigationEventArgs e) { base .OnNavigatedTo(e); CarHeader.DataContext = CarDataStore.Car; DataContext = currentFillup = State.ContainsKey(CURRENT_FILLUP_KEY) ? (Fillup) this .State[CURRENT_FILLUP_KEY] : new Fillup() { Date = DateTime .Now }; hasUnsavedChanges = State.ContainsKey(HAS_UNSAVED_CHANGES_KEY) ? ( bool )State[HAS_UNSAVED_CHANGES_KEY] : false ; } * This source code was highlighted with Source Code Highlighter .
  25. private const string CURRENT_FILLUP_KEY = "CurrentFillup" ; private const string HAS_UNSAVED_CHANGES_KEY = "HasUnsavedChanges" ; private Fillup currentFillup; private bool hasUnsavedChanges; protected override void OnNavigatedFrom(NavigationEventArgs e) { base .OnNavigatedFrom(e); if (cacheChanges) { CommitTextBoxes(); this .State[CURRENT_FILLUP_KEY] = currentFillup; this .State[HAS_UNSAVED_CHANGES_KEY] = hasUnsavedChanges; } } protected override void OnNavigatedTo(NavigationEventArgs e) { base .OnNavigatedTo(e); CarHeader.DataContext = CarDataStore.Car; DataContext = currentFillup = State.ContainsKey(CURRENT_FILLUP_KEY) ? (Fillup) this .State[CURRENT_FILLUP_KEY] : new Fillup() { Date = DateTime .Now }; hasUnsavedChanges = State.ContainsKey(HAS_UNSAVED_CHANGES_KEY) ? ( bool )State[HAS_UNSAVED_CHANGES_KEY] : false ; } * This source code was highlighted with Source Code Highlighter .
private const string CURRENT_FILLUP_KEY = "CurrentFillup" ; private const string HAS_UNSAVED_CHANGES_KEY = "HasUnsavedChanges" ; private Fillup currentFillup; private bool hasUnsavedChanges; protected override void OnNavigatedFrom(NavigationEventArgs e) { base .OnNavigatedFrom(e); if (cacheChanges) { CommitTextBoxes(); this .State[CURRENT_FILLUP_KEY] = currentFillup; this .State[HAS_UNSAVED_CHANGES_KEY] = hasUnsavedChanges; } } protected override void OnNavigatedTo(NavigationEventArgs e) { base .OnNavigatedTo(e); CarHeader.DataContext = CarDataStore.Car; DataContext = currentFillup = State.ContainsKey(CURRENT_FILLUP_KEY) ? (Fillup) this .State[CURRENT_FILLUP_KEY] : new Fillup() { Date = DateTime .Now }; hasUnsavedChanges = State.ContainsKey(HAS_UNSAVED_CHANGES_KEY) ? ( bool )State[HAS_UNSAVED_CHANGES_KEY] : false ; } * This source code was highlighted with Source Code Highlighter .

In this code, the overloaded method OnNavigatedFrom first checks whether it should cache state data. The FillupPage class initializes the cacheChanges field to true , but sets it to false whenever normal navigation occurs (that is, when the user clicks the Save or Back button). Thus, the page caches data only when navigation occurs as a result of deactivation.

If the changes have been cached, the OnNavigatedFrom method applies the values ​​of the text fields to the bound (bound) object (stored in the currentFillup field), and then stores the currentFillup and hasUnsavedChanges values in the State dictionary. Applying (committing) text field values ​​is necessary because data bindings usually occur when the control loses focus, which does not happen automatically when the application is deactivated.

The OnNavigatedTo method sets the CarHeader element to the DataContext property and then tries to retrieve the stored values ​​from the State dictionary. If values ​​are present in the dictionary, they are used to set the page's DataContext property in addition to the currentFillup and hasUnsavedChanges fields . Otherwise, default values ​​are used.

This implementation provides basic tombstoning support, but does not store every aspect of page status. In particular, this implementation does not store a value indicating which text field is in focus, nor does it store the cursor position and selection state of the text field in focus. The importance of maintaining this state information depends on the application.

Tip:
When implementing tombstoning support, do not forget to test it thoroughly. To do this, go to each page (using an emulator or an actual device), click the Start button, and then click the Back button. Be sure to check each state of each page of your application and make sure that reactivation always restores the state as expected.

If you are testing tombstoning support in an emulator in Visual Studio in debug mode, you will notice that the debugger sometimes interrupts the connection when you deactivate your application. In this case, the application will seem to hang on the “recovering” page when you re-activate it. You can solve this problem by simply going to Visual Studio and pressing F5 again. The application will then be restarted and re-activated.

When to perform actions in the application


You can write code for each phase of the application life cycle. We have described above how to respond to page navigation in order to load data and implement tombstoning support. Below will be described the general life cycle of the application and the pages and the general types of code that can be written for each stage of the life cycle are indicated.

The Windows Phone application starts when the user clicks on the icon or tile of the application, and closes when the user clicks the back button on the first page of the application. External events (for example, when the “Start” button is pressed) can deactivate the application at any time, potentially causing it tombstoning and forcing it to close. Reactivation restarts the application and gives it the ability to restore its previous state. These stages of startup and shutdown in the life cycle are represented as Launching, Activated, Closing, and Deactivated events of the PhoneApplicationService class.

As soon as the application is launched, the start page opens automatically, after which the user can switch to additional pages. If the application is deactivated and reactivated, it moves to the previously active page.

When an application first goes to a page or goes back to a page after deactivation and reactivation, an instance of the page is created, its constructor is called, and then the OnNavigatedTo method of this page is called, if they are present. Shortly before moving to another page, exit or deactivation, the OnNavigatedFrom method is called. Page instances are reused only if the user navigates back to previously visited pages and the application was not deactivated after this visit. In this case, the application calls the OnNavigatedTo and OnNavigatedFrom methods, as before, but without calling the constructor before that.

The following image shows the overall life cycle of the application and page.

image

Typically, you will use Launching, Activated, Closing, and Deactivated events to initialize and maintain application state. However, when these events occur, the phone is still in the process of loading or unloading the application, potentially causing significant delays. To avoid increasing these delays, you should always avoid time-consuming operations in the handlers for these events.

Usually, you will use the page's overloaded OnNavigatedTo and OnNavigatedFrom methods to initialize the page state and perform or run time-consuming operations, such as loading and saving data. When the OnNavigatedTo method is called, the application and pages have already finished loading and are available for use. When the OnNavigatedFrom method is called, the application and pages have not yet begun to be unloaded.

Certification Requirement:
Your application should render its first screen within 5 seconds after launch and start responding to user actions within 20 seconds.

To meet the first requirement, you can display a splash screen. To meet the second requirement, you can load data only when it is needed and run labor-intensive operations asynchronously, possibly using BackgroundWorker. However, even if you use a background thread, you must run it in the OnNavigatedTo overloaded method, rather than in the Launching or Activated event handlers, to avoid an increase in the launch time.

Certification Requirement:
When the application is unloaded, it must also complete all operations within 10 seconds upon a request to close or deactivate, otherwise an exception will be thrown and the application will be terminated. To meet this requirement, you should consider saving data as soon as they become available, or gradual saving if there are large amounts of data.

Next part

Source: https://habr.com/ru/post/118459/


All Articles