EvenTiles from Start to Finish - Part 8
Join the DZone community and get the full member experience.
Join For FreeIn the previous episode of this series about how to develop a Windows Phone application from scratch we talked about Fast Application Switching and Tombstoning. We saw how Visual Studio 2010 can help us testing Tombstoning scenarios. We also covered how to preserve application data when the application is interrupted by other applications and how to restore that data when returning to the foreground.
Right now we will extend our knowledge about Fast Application
Switching and Tombstoning by trying to exactly restore a page after the
application returns from the background. For that, we will take a look
at the following scenario.
The user is entering data in the textbox inside the SettingsPage. This
means that a keyboard is visible and that the textbox has input focus
and a blinking cursor at the location where data is entered. Sometime in
the middle of entering text, the user hits the start button to activate
another application, to return to our application only after a while.
Even though we have stored all data the user entered (because we are
saving the contents of the textbox when navigating away from the
SettingsPage), the text box does not have focus when the user returns to
the SettingsPage, nor a cursor positioned at the right location. In
order to restore the exact same situation, we need to store additional
data when navigating away from the SettingsPage. This leads to another
challenge. To store the local page state when we are navigating away
from the SettingsPage we can use the following code:
Saving the Page State:
protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e) { if (!e.IsNavigationInitiator) { TextBox tb = FocusManager.GetFocusedElement() as TextBox; if (tb != null) { this.State[keySelectionLength] = tb.SelectionLength; this.State[keySelectionStart] = tb.SelectionStart; } } App.ActualSecBackContent = tbBackContent.Text; base.OnNavigatedFrom(e); }
Each time OnNavigatedFrom is called, there is a possibility that the
application is moved to the background. If so, the property IsNavigationInitiator is false.
If the application is moved to the background, we check if the textbox
currently has focus. If so, we will store the location of the cursor by
adding entries for both the SelectionStart (location where the cursor
is) and SelectionLength. If on the other hand the textbox does not have
focus, we don’t have to store page state information, just the Text
property of the textbox.
Retrieving page state information back can be done in the OnNavigatedTo method as follows:
Restore the Page State:
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e) { tbBackContent.Text = App.ActualSecBackContent; btnRestore.Visibility = tbBackContent.Text.Equals(App.DefaultSecBackContent) ? System.Windows.Visibility.Collapsed : System.Windows.Visibility.Visible; if (this.State.ContainsKey(keySelectionLength)) { tbBackContent.SelectionLength = (int)this.State[keySelectionLength]; tbBackContent.SelectionStart = (int)this.State[keySelectionStart]; focusToTextBox = true; } base.OnNavigatedTo(e); }
However, it is not possible to get the focus back to the textbox control in the OnNavigatedTo method, because the different UI elements are not yet initialized when OnNavigatedTo is called. That is the reason to set a boolean variable to true and actually give the textbox focus when the Loaded event on the page is fired. If the application is returning from the background and focusToTextBox is set to true, the tbBackContent textbox will get focus:
Restore textbox input focus:
private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e) { if (focusToTextBox) { tbBackContent.Focus(); } }
If an application would always be tombstoned, this would be sufficient
to store / restore state information for the page and to restore the
input focus if the textbox had focus when the application was put in the
background. However, with Windows Phone Mango, applications can benefit
from the Dormant state, where they stay in memory even though being in
the background. There is not really a clear distinction from a
developer’s point of view between Dormant and Tombstoned, except for the
fact that in case of returning from being Tombstoned, the page
constructor is executed, something that is not the case when the
application returns from Dormant since the application was still in
memory. As a consequence, returning from the Dormant state also means
that the Loaded event on the page is not fired. So, even though
returning to the foreground is faster if we were in the Dormant state,
we need some additional logic to give the textbox focus in this case. In
order to distinguish between Dormant and Tombstoned, it is possible to
set a boolean variable in the constructor of a page to true and check
that variable in the OnNavigatedTo method:
Dormant vs Tombstoned:
private bool focusToTextBox; private bool pageConstructed; public SettingsPage() { InitializeComponent(); pageConstructed = true; }
The value of the pageConstructed variable determines if we are returning
from a Dormant state to the foreground (false) or not. If we are not
returning from a Dormant state, we need to determine in OnNavigatedTo if
we returned from a Tombstoned state in order to optionally set the
focus to the textbox. However, if we are returning from a Dormant
situation, the OnNavigatedTo method itself must be used to set focus to
the textbox if needed. The modified OnNavigatedTo method looks like
this:
Complete Page Reconstruction:
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e) { tbBackContent.Text = App.ActualSecBackContent; btnRestore.Visibility = tbBackContent.Text.Equals(App.DefaultSecBackContent) ? System.Windows.Visibility.Collapsed : System.Windows.Visibility.Visible; if (this.State.ContainsKey(keySelectionLength)) { tbBackContent.SelectionLength = (int)this.State[keySelectionLength]; tbBackContent.SelectionStart = (int)this.State[keySelectionStart]; if (!pageConstructed) { tbBackContent.Focus(); } else { focusToTextBox = true; } } base.OnNavigatedTo(e); }
The following video shows how to save and restore the page state for
the SettingsPage of EvenTiles for the different application execution
states:
Update after video creation: Even though it seems in the video that the application is working properly both when returning from Dormant and from Tombstoning states, this is not entirely the case. Even though the focus of the Textbox is restored properly when needed, the Textbox will also get focus each and every time we return from the background, with the exception of the first time. The reason for that is that the dictionary entries in the Page.State collection were not deleted after usages in the OnNavigatedTo method. The source code for EvenTiles contains a fix for this undocumented application feature.
If you want to take a look at the source code that we have available
for EvenTiles so far, you can download the entire solution belonging to
this episode:
Download EvenTiles Episode 8 Source Code
After downloading and unzipping the sample code, you can open the
EvenTiles solution in Visual Studio 2010 Express for Windows Phone. You
must have the Windows Phone SDK 7.1
installed on your development system to do so. If you have a developer
unlocked phone you can deploy the application to your phone, if you
don’t have a developer unlocked phone you can still experiment with this
application inside the emulator.
In the next episode of EvenTiles we will finally get to the heart and soul of the application, when we are going to create a Secondary Tile.
Source: http://mstruys.com/2011/12/14/eventiles-from-start-to-finishpart-8/
Opinions expressed by DZone contributors are their own.
Comments