Vermont Code Camp Presentation Materials

Many thanks to the organizers and attendees of this year’s Vermont Code Camp.   This event continues to set the bar for excellence, and a ton of credit is due to Julie Lerman, Rob Hale, and the rest of the volunteers who all clearly work quite hard to pull it all together.

I have uploaded the code and content from my “What’s New in Windows Phone 7.1 Silverlight Development”, and they can be downloaded from here.

Advertisements

Boston Azure User Group Presentation Materials

Many thanks to the organizers and attendees of the Boston Azure User Group where I had the chance to speak this past week on Developing Cloud-Enabled Windows Phone Applications with Windows Azure.  I hope everyone who attended enjoyed the presentation as much as I enjoyed doing it.  I certainly appreciate everybody having stuck through considering the A/C glitch causing the room temperature to get a little uncomfortable.

Speaking of weather, I think my house is now as prepared as it is going to be for the upcoming arrival of hurricane Irene to New Hampshire…I really didn’t think I’d be dealing with these anymore after my 15 years in Florida – that we “paid our dues” in New England with our annual rounds of Nor’easters and other winter “fun.”  Nonetheless, the slide deck and code from the presentation have been posted, and can be found here.

The sample code is broken into 5 parts across 4 solutions as follows:

  1. Membership (Windows Azure Toolkit for Windows Phone)
  2. Storage (Windows Azure Toolkit for Windows Phone)
  3. Notification Services (Windows Azure Toolkit for Windows Phone)
  4. AppFabric Service Bus
  5. OData (Azure Data Marketplace and SQL Azure)

Key “markers” have been placed into the code files as comments that start with the word “NOTE” (a handy way to see *most* of them is to make use of the Visual Studio Task List pane, however, there are a few in the config files that don’t get picked up by this pane.)  The code has been sanitized to point to local storage and/or to remove any keys I had put in that were specific to the sites and accounts I was using for the demo.  Please substitute your own private values where necessary.

Creating Custom Ringtones in Windows Phone Mango

Now that I have upgraded my phone to the Windows Phone 7.1 Developers’ Preview, one of the features I’ve been anxious to try out is Custom Ringtones – the default tones and the ones provided by AT&T are “interesting”, but they’re just not “me.”  Windows Phone 7.1 (AKA Mango) supports custom ringtones – but how do you go about making that happen?

IMPORTANT – The information below is based on Windows Phone 7.1 (AKA Mango) Beta 2, with a phone and the related Zune software upgraded to use the Developer Preview.

The available ringtones on the phone are segmented into groups which can be seen by going to Settings / Ringtones + Sounds and/or Contact / Edit / Ringtone (the latter location is used to override the default ringtone and set a per-contact ringtone.)  The default collection of ringtones that are included by the phone OS, those provided by the carrier, and any custom ringtones installed by the user.  Custom and OEM-provided ringtones can be deleted (for pruning the available ringtone list) whereas the ringtones included with the Phone OS cannot.

Custom ringtones are audio files that are “registered” with the phone OS in a certain way – more on this in a moment.  However, in order to be registered, an audio file must meet the following criteria:

  • It must be either a WMA or an MP3 file
  • It must be 39 seconds or shorter in length
  • It must be smaller than 1MB in size
  • It cannot be copy protected / have DRM restrictions

Creating Custom Ringtone Files

So what do you need to create a custom ringtone file that fits this criteria?  While there are several tools that can be used, I’ll highlight 2 here – Expression Encoder and Audacity.  Expression Encoder is part of Microsoft’s Expression Suite.  As of this writing, there are both free and pro versions available, and while I happen to have Pro (available as part of my MSDN Subscription), the audio features should be part of both SKUs.  Expression Encoder succeeds the Windows Media Encoder, and although it is primarily targeted at video projects, it is usable for audio projects.

To get started with Expression Encoder, launch the application and select a “Transcoding Project” in the New Project dialog.  To load the audio file, select either Import from the File menu, or locate the file in Windows Explorer and drag it onto the application.  The file will be loaded into the editing timeline, and its metadata will be displayed.  Using the editing controls within Encoder, the section of interest for the ringtone can be isolated.  Since there is no waveform monitor within Encoder, this is exercise must largely be performed by ear and with an eye on the time displayed in the timeline.  (Note – a full discussion of editing within the Encoder product is beyond the scope of this discussion.)  Once the desired segment of audio has been isolated, the specific WMA format can be selected from the Encode toolstrip, and the Audio property panel can be used to set the target bitrate mode, bitrate, channel information, sample rate, and bit depth (these settings push and pull against each other to determine audio quality vs file size.  Remember, this is a ringtone, and there are limits to the file size.  Audio quality is probably negotiable here.)  The Metadata toolstrip can be used to set the clip;s metadata attributes (in particular, Title and Genre are important here), and the Output toolstrip can be used to determine the file output.  When ready, selecting Encode or Encode Selected Item from the File menu starts creating the new ringtone file.

SNAGHTML80d969d

Audacity is a free, open source, cross-platform sound editor.  In addition to downloading the Audacity application itself, for these purposes 2 add-ons should be considered – the LAME MP3 encoder (if MP3 files are the desired output), and the FFmpeg import/export library (if WMA files will be imported or exported.)  Links to these add-ons can be found at the Audactiy download site here.  To start editing a file, select Import from the File menu, or drag the file into the application.  Audacity does display a waveform synchronized to the timeline, making the audio editing experience more visual than in Expression Encoder.  Once the target section of the file has been isolated, Export or Export Selection can be selected from the File menu.  From here, the type of file being exported can be chosen (WMA or MP3 for ringtones), and depending on the selection, encoding options can be chosen.  Note that there are far fewer encoding options for WMA here than in Expression Encoder.  Once a target file location and options are selected, the metadata editor will be displayed, where metadata for the output file can be set. 

SNAGHTML8192f82

Regardless of what is set in the encoding applications above, the details tab in the file properties dialog can be used to set the metadata.  The Title property controls what is displayed when the file is shown in the Custom Ringtones group in the phone.  The Genre value is actually quite important – in order to use the Zune software to load the ringtone, it must be set to “Ringtone.”

SNAGHTML81f29f7

Adding Ringtones Using Zune Software

To manually transfer the ringtone, make sure the ringtone file that was just created is in one of the configured music folders within the Zune software, as pictured below. 

SNAGHTML822444a

Set the file (or fill folder) to be synced with the phone device.  The next time the phone is plugged in, the file will be placed on the phone.  Because its genre is set to “ringtone”, the files will not appear in the phone’s audio collection, and will appear in the list of custom ringtones.

image

Programmatically Adding Ringtones

If the ringtone files are not originating on the phone user’s desktop and/or using the Zune software is not practical, there is a mechanism for adding ringtones programmatically.  This would be useful, for example, to provide an application that allows ringtones to be selected from an internet site or related resource.  The SaveRingtoneTask takes center stage for programmatically setting ringtones.  For SaveRingtoneTask, the DisplayName property determines the name the ringtone will be displayed with in the Custom Ringtones section, and the Source property provides a Uri to the location of the ringtone file to be used.  This Uri typically points to a location in Isolated Storage, using the URI syntax for accessing Isolated Storage, as shown below (notice the similarity with the Uri used for the Connection String specified when accessing SQL CE databases in the WP 7.1 API.  There is some discussion that the Source Uri will also support the appdata prefix syntax that is available for read-only files that are included as part of the app’s payload in the Xap file, but I have yet to test this specific functionality.) 

   1: saveRingtoneChooser.DisplayName = "My Ringtone";

   2: saveRingtoneChooser.Source = new Uri(@"isostore:/myringtone.wma");

   3: saveRingtoneChooser.IsShareable = true;

   4: saveRingtoneChooser.Show();

Note that the file in Isolated Storage is “copied” to the internal ringtone location on the phone…if the application that ran the Chooser is subsequently uninstalled (which clears Isolated Storage for that application), the ringtone persists until it is explicitly deleted from the Custom Ringtone collection.  Also, in the case of the web-based ringtone provider example discussed above, it may be prudent to use the Background Transfer Service to queue the selected ringtone download, then process the file once it has been fully downloaded.

A Note About the Audio Files Used in this Example

The audio files used in this discussion are ripped from CD’s that are physically in my own personal collection (my taste in music notwithstanding.)  Please be sure to perform your own copyright research prior to launching any ringtone software / services.

Showing the Onscreen Keyboard in Silverlight OOB Applications

One of the “interesting” things about Silverlight apps running on Windows is that on touch/tablet systems, textboxes in Silverlight do not display a popup button to use for bringing up the Windows onscreen keyboard when they have focus, whereas native applications do.

image
WPF / Native Window following a “Touch” in a textbox

image
Silverlight OOB Window following a “Touch” in a textbox

The onscreen keyboard is actually present in the Silverlight case – it is usually just “conveniently” tucked against the left side of the screen – and experience has shown me that until you actually show or describe to someone where it is, they will usually not find it on their own.  Tap it once, and it “peeks” out a little bit.  Tap it again, and it is brought to the center of the screen.  Hit the close button, and it returns to its tucked away position on the side of the screen.

I have been asked several times for an option to show the onscreen keyboard from within a Silverlight application in a more consistent and user-friendly fashion.  It turns out that for Silverlight Out of Browser applications running with Elevated Trust, there is an option – COM Automation can be used to invoke the process that displays the onscreen keyboard, or Text Input Panel (TIP).

Locating the Process

As of Windows Vista, the TextInputPanel handles the Tablet Input Panel (TIP).  This is implemented in the file TabTip.exe, which exists in the directory <Program Files>\Common Files\Microsoft Shared\ink – this is true both in 64-bit and 32-bit versions of Windows.  (Note – I have verified this myself only on Windows 7.)  See the following site for more information about the TIP: http://msdn.microsoft.com/en-us/library/ms701746(VS.85).aspx.

Normally, to locate the needed path, the Environment.GetFolderPath method would be used.  However, when called on a 64-bit system from Silverlight with SpecialFolder.CommonProgramFiles as the parameter, it returns the path to the x86 Program Files directory…not the one that is needed in this case.  However, using the scripting shell’s ExpandEnvironmentStrings method can get the correct value, as follows:

   1: dynamic shell = AutomationFactory.CreateObject("WScript.Shell");

   2: String commonPath = shell.ExpandEnvironmentStrings("%CommonProgramW6432%");

   3:  

   4: // This path is the same for both 32 and 64-bit installs of Windows

   5: String filePath = System.IO.Path.Combine(commonPath, @"microsoft shared\ink\TabTip.exe");

Information about the CommonProgramW6432 Environment Variable can be found at this link: http://msdn.microsoft.com/en-us/library/aa384274(VS.85).aspx.

Showing the Onscreen Keyboard

Now that the necessary program has been located, it simply needs to be run to show the keyboard (or to bring it up onscreen, in case the keyboard app is running, but “hidden” along the margin, as pictured above.  To do this, simply call ShellExecute, passing in the path calculated above:

   1: dynamic application = AutomationFactory.CreateObject("Shell.Application");

   2: application.ShellExecute(filePath, "", "", "open", 1);

The full code listing for a ShowKeyboard helper method is shown below:

   1: public static class KeyboardHelper

   2: {

   3:     public static void ShowKeyboard()

   4:     {

   5:         if (AutomationFactory.IsAvailable)

   6:         {

   7:             try

   8:             {

   9:                 // Ensure Windows 7 or Windows Server 2008 R2

  10:                 // OS Version # - http://msdn.microsoft.com/en-us/library/ms724832(VS.85).aspx

  11:                 if (Environment.OSVersion.Platform == PlatformID.Win32NT

  12:                     && Environment.OSVersion.Version >= new Version(6, 1))

  13:                 {

  14:                     // Get the path to the Common Program Files directory (not the x86 version...)

  15:  

  16:                     // Environment.GetFolderPath returns the wrong path (x86 branch on 64-bit systems.)

  17:                     // String commonPath = Environment.GetFolderPath(Environment.SpecialFolder.CommonProgramFiles);

  18:  

  19:                     dynamic shell = AutomationFactory.CreateObject("WScript.Shell");

  20:                     String commonPath = shell.ExpandEnvironmentStrings("%CommonProgramW6432%");

  21:  

  22:                     // This path is the same for both 32 and 64-bit installs of Windows

  23:                     String filePath = System.IO.Path.Combine(commonPath, @"microsoft shared\ink\TabTip.exe");

  24:  

  25:                     // Bring up the TIP - http://msdn.microsoft.com/en-us/library/ms701746(VS.85).aspx

  26:                     dynamic application = AutomationFactory.CreateObject("Shell.Application");

  27:                     application.ShellExecute(filePath, "", "", "open", 1);

  28:                 }

  29:             }

  30:             catch (Exception ex)

  31:             {

  32:                 Debug.WriteLine(ex);

  33:             }

  34:         }

  35:     }

  36: }

What’s Next?

I have shown how to programmatically show the TIP…as far as how to get there, that is left as an exercise for the reader.  In some cases, adding a launcher (such as a “show keyboard” button) somewhere in the UI may be an acceptable option – it is certainly the simplest.  To approximate the behavior seen in native applications, more work is required.  This includes showing a UI control to display the TIP, which is only displayed if the user accesses the textbox control via touch input.  This can be determined by using the Silverlight Multitouch Input APIs, or a helper library such as LightTouch or the Native Extensions for Silverlight

CT Code Camp 4 Presentation Materials

I have uploaded the content from my talk at the Connecticut .Net Developers’ Group Code Camp 4 from today (6/18/2011).  The code and content  from my “What’s New in Windows Phone 7.1 Silverlight Development” are available here.

Many thanks to SB Chatterjee and his team for putting together the event.  Also thank you to the attendees for some great questions and discussion during and after the session (and yes, I did make it back home in time to attend my daughter’s recital.)

NH .Net Code Camp 3 Presentation Materials

I have uploaded the content from my 2 talks at the NH .Net Code Camp 3 event from yesterday (6/4/2011). 

  • The code and material for my first talk – Introduction to Windows Phone 7 Development with Silverlight – are available here.
  • The code and material for my second talk –  What’s New in Windows Phone 7.1 Silverlight Development – are available here.

As is usually the case, the code has been sanitized, which involves the removal of my personal Bing Maps developer key.  For information on how to obtain your own map key, please check out the Bing Maps Developer Portal.

Many thanks to Patty, Udai, and Pat for hosting another fun event. 

An Examination of State and Navigation Issues Related to the Windows Phone DatePicker & TimePicker Controls

I recently ran into an interesting issue when using the DatePicker control that is available in the Silverlight for Windows Phone Toolkit.  At first glance it looked like everything was working fine, but on closer inspection, I noticed that it seemed that the date I was selecting was not being returned from the control.  Once I figured out what was happening, I realized the same thing can happen when using the related TimePicker control.

The Setup

I discovered this when working on a Master/Details application.  The Master list provided a view of a list of items, where each item contains a set of properties that includes a Date.  Through the Master page, the user can select to edit an item, which navigates to a dedicated Editing page and opens the details of the item to edit…a fairly common scenario.  The general logic is as follows:

  • The edit command is executed (button pushed, etc.)
  • A request to navigate to the EditingPage is made through the NavigationService.  The Id of the item to edit is placed in the query string of the target Url as follows:
    NavigationService.Navigate(new Uri("/EditingPage.xaml?Id=" + selectedItem.Id, UriKind.Relative));
  • In the EditingPage OnNavigatedTo handler, the id of the item to edit is pulled from the query string and the object that contains the item details is retrieved (in this case, the value is pulled from  a list that is owned by the Application instance.)
  • The EditingPage markup includes a DatePicker control that is databound to the Date property contained in the item details object.

Excerpt form Page Markup:

Code Snippet
  1. <TextBlock Grid.Row="0" Grid.Column="0" Text="Id: " VerticalAlignment="Center"/>
  2. <TextBlock Grid.Row="1" Grid.Column="0" Text="Date: " VerticalAlignment="Center"/>
  3. <TextBlock Grid.Row="2" Grid.Column="0" Text="Some Text: " VerticalAlignment="Center"/>
  4.  
  5. <TextBox Grid.Row="0" Grid.Column="1" Text="{Binding Path=Id, Mode=TwoWay}" />
  6. <toolkit:DatePicker Grid.Row="1" Grid.Column="1" Value="{Binding Path=DateOfInterest, Mode=TwoWay}"/>
  7. <TextBox Grid.Row="2" Grid.Column="1" Text="{Binding Path=SomeRandomText, Mode=TwoWay}" />

The OnNavigatedTo override code follows:

Code Snippet
  1. protected override void OnNavigatedTo(NavigationEventArgs e)
  2. {
  3.     base.OnNavigatedTo(e);
  4.     if (NavigationContext.QueryString.ContainsKey("Id"))
  5.     {
  6.         var idText = NavigationContext.QueryString["Id"];
  7.         if (Int32.TryParse(idText, out _originalItemId))
  8.         {
  9.             var itemToEdit = ((App)(Application.Current)).CurrentViewModel.TestDataItems.FirstOrDefault(x => x.Id == _originalItemId);
  10.             _itemBeingEdited = new TestData();
  11.             itemToEdit.CopyTo(_itemBeingEdited);
  12.         }
  13.     }
  14.     DataContext = _itemBeingEdited;
  15. }

A Few Words About the Controls

The DatePicker and TimePicker controls are included in the Silverlight for Windows Phone Toolkit.  The Toolkit consists of a set of controls and other utilities that are released “out of band” from the regular tools’ release.  The first formal release of this toolkit was in November 2010, followed by a February 2011 update.  In addition to not having to wait for a new update to the full SDK for these tools, they are also published on CodePlex with full source code, which provides great insight into how things work, both for educational and forensic purposes.

The DatePicker and TimePicker controls offer a touch-optimized experience for selecting the corresponding values.  The value is initially presented in the phone UI in text format.  When the control is selected, a series of 3 rotating lists are presented for selecting a specific value, as illustrated below:

image

“Control View” for Date Picker & TimePicker controls

SNAGHTML324d104 SNAGHTML3244a77

The DatePicker Control In “Picker” View

The TimePicker Control in “Picker” View

 

Neither Fish nor Fowl

At the heart of the problem is the fact that although it may not be immediately obvious, the DatePicker and TimePicker controls actually use full-blown PhoneApplicationPage pages to present their selection lists (though the fact that they contain ApplicationBar buttons is probably a big hint.)  However, in some regards, these pages do not behave like “normal” pages – for example, when the application is deactivated and subsequently reactivated, you are not returned to the picker-page, but rather to your page that contains the control.  The picker controls go to some length to simulate this popup behavior:

  • In the OnNavigatedFrom handler, if the destination Uri indicates something external to the application, then the current value is added to the picker’s Page State dictionary with the key specified by the StateKey_Value const:
    Code Snippet
    1. // Save Value if navigating away from application
    2. if ("app://external/" == e.Uri.ToString())
    3. {
    4.     State[StateKey_Value] = Value;
    5. }
    • WHOA!  Did you see that?  Apparently there’s a “magic uri” that can be used to detect that the application is on the verge of being deactivated.  That one gets filed away under the “interesting stuff to know about” heading.
  • In the OnNavigatedTo handler, the page’s State dictionary is examined for this StateKey_Value, and if present, the value is retrieved from this entry, and then the NavigationService is called to back out of the page.
    Code Snippet
    1. // Restore Value if returning to application (to avoid inconsistent state)
    2. if (State.ContainsKey(StateKey_Value))
    3. {
    4.     Value = State[StateKey_Value] as DateTime?;
    5.  
    6.     // Back out from picker page for consistency with behavior of core pickers in this scenario
    7.     if (NavigationService.CanGoBack)
    8.     {
    9.         NavigationService.GoBack();
    10.     }
    11. }

Aha!

So now we have a page that is pretending to be a popup…we’ve all done something like this, and know from experience that inevitably it leads to problems…if you aren’t aware of the masquerade and don’t anticipate the “true” behavior, complications soon follow.  In this case, “closing the popup” results in a traditional page navigation sequence…including the execution of the OnNavigatedTo handler, which dutifully retrieves the Id of the item being edited from the query string, and loads the object to be edited into the page, which is then bound to the controls, including the DatePicker control….uh-oh.  Wait a minute!  How does the list-page communicate its selection back to the original page?  Once again it is time to go back to the toolkit source code.

  • When the user brings up the picker page by selecting the control on the editing page, the control locates the current PhoneApplicationFrame instance that is holding the pages in the current application (the RootFrame object)
  • A handler is attached to the frame’s Navigated event
  • The frame is told to navigate to the picker page
  • In the handler mentioned above, a determination is made to see whether the destination page is the original page that hosts the control or the picker page.
  • If the target page is the original hosting page, the frame event handlers are detached and the control’s Value is set to the value that was selected on the page.
    • This value is ultimately backed by a dependency property, which includes metadata information that (eventually) raises a ValueChanged event from the control.

It is important to note the relationship between the Page Navigation override methods and the Frame Navigation events:

  • Frame Navigating Event
  • Source Page OnNavigatingFrom Handler
  • Frame Navigated Event
  • Source OnNavigatedFrom Handler
  • Target Page OnNavigatedTo Handler

Note that the OnNavigatedTo handler is invoked a few steps AFTER the firing of the Navigated event.  Therefore, any values set in the Navigated event can easily be overwritten in the OnNavigatedTo handler, which is exactly the case that I ran into.  The control’s value was being set to the value selected in the picker page, which was in fact triggering all the necessary bindings.  Then the code in the OnNavigatedTo override was resetting this with the original object value. 

That’s Nice…Now What?

As I see it, there is a general solution that can be applied, with two possible manifestations.  I have to admit that they both feel a little awkward…maybe I’ll stumble into something down the road that leaves me feeling less “dirty.”  With that wonderful preamble, let’s look at the solution.

The general solution is to record that the current navigation is being triggered as a result of a call to the picker control and use that information to prevent and/or repair the undesired value override.  I mentioned there were (at least) two ways to do this.

The first approach involves using the OnNavigatedFrom override to detect if the target page is a DatePickerPage (or TimePickerPage), and if so, record a token in State that a Picker operation is in-progress. In OnNavigatedTo, detect this token, retrieve the value that must have been set when the control was updated, and bypass the use of the query string id to reset the underlying value. (This is missing something for tombstoning, which is detailed below.)

Code Snippet
  1. protected override void OnNavigatedFrom(NavigationEventArgs e)
  2. {
  3.     if (e.Content is DatePickerPage)
  4.     {
  5.         State["WentToDatePicker"] = true;
  6.     }
  7.  
  8.     base.OnNavigatedFrom(e);
  9. }
  10.  
  11. protected override void OnNavigatedTo(NavigationEventArgs e)
  12. {
  13.     base.OnNavigatedTo(e);
  14.  
  15.     if (State.ContainsKey("WentToDatePicker"))
  16.     {
  17.     }
  18.     else if (NavigationContext.QueryString.ContainsKey("Id"))
  19.     {
  20.         var idText = NavigationContext.QueryString["Id"];
  21.         if (Int32.TryParse(idText, out _originalItemId))
  22.         {
  23.             var itemToEdit = ((App)(Application.Current)).CurrentViewModel.TestDataItems.FirstOrDefault(x => x.Id == _originalItemId);
  24.             _itemBeingEdited = new TestData();
  25.             itemToEdit.CopyTo(_itemBeingEdited);
  26.         }
  27.     }
  28.     DataContext = _itemBeingEdited;
  29. }

In the second approach, the control’s ValueChanged event that was described above can be used in a similar value to determine that a picker operation is in progress, which can then be used to bypass the use of the query string id, as mentioned above.

Code Snippet
  1. private Boolean _isNavigationfromPicker;
  2.  
  3. private void HandleDateControlValueChanged(Object sender, DateTimeValueChangedEventArgs e)
  4. {
  5.     _isNavigationfromPicker = true;
  6. }
  7.  
  8. protected override void OnNavigatedTo(NavigationEventArgs e)
  9. {
  10.     base.OnNavigatedTo(e);
  11.  
  12.     if (_isNavigationfromPicker)
  13.     {
  14.         _isNavigationfromPicker = false;
  15.     }
  16.     else if (NavigationContext.QueryString.ContainsKey("Id"))
  17.     {
  18.         var idText = NavigationContext.QueryString["Id"];
  19.         if (Int32.TryParse(idText, out _originalItemId))
  20.         {
  21.             var itemToEdit = ((App)(Application.Current)).CurrentViewModel.TestDataItems.FirstOrDefault(x => x.Id == _originalItemId);
  22.             _itemBeingEdited = new TestData();
  23.             itemToEdit.CopyTo(_itemBeingEdited);
  24.         }
  25.     }
  26.     DataContext = _itemBeingEdited;
  27. }

Bonus Round – Tombstoning Support in the Editing Page

It is generally a good practice to add support for “remembering” the values that have been changed when the application is deactivated and restoring them when the application is reactivated, in order to save the user’s hard work on the page.  In that case, in OnNavigatedFrom the necessary details can be preserved (the code below uses a serializable object and just inserts that into the Page State dictionary), and in OnNavigatedTo, retrieve the value if necessary and use it for editing if present, and possibly override the saved date value if necessary.  If the value is not available for retrieval, the page navigation must be the result of the initial request, so the Id should be retrieved from the query string, and subsequently the item to be edited retrieved form its source.

Code Snippet
  1. protected override void OnNavigatedFrom(NavigationEventArgs e)
  2. {
  3.     if (e.Content is DatePickerPage)
  4.     {
  5.         State["WentToDatePicker"] = true;
  6.     }
  7.  
  8.     State["ItemEditingState"] = _itemBeingEdited;
  9.     base.OnNavigatedFrom(e);
  10. }
  11.  
  12. protected override void OnNavigatedTo(NavigationEventArgs e)
  13. {
  14.     base.OnNavigatedTo(e);
  15.  
  16.     DateTime? tempOverrideDate = null;
  17.     if (State.ContainsKey("WentToDatePicker") && _itemBeingEdited != null)
  18.     {
  19.         tempOverrideDate = _itemBeingEdited.DateOfInterest;
  20.     }
  21.  
  22.     if (State.ContainsKey("ItemEditingState"))
  23.     {
  24.         _itemBeingEdited = State["ItemEditingState"] as TestData;
  25.         if (tempOverrideDate.HasValue)
  26.         {
  27.             if (_itemBeingEdited != null)
  28.             {
  29.                 _itemBeingEdited.DateOfInterest = tempOverrideDate.Value;
  30.             }
  31.         }
  32.     }
  33.     else if (NavigationContext.QueryString.ContainsKey("Id"))
  34.     {
  35.         var idText = NavigationContext.QueryString["Id"];
  36.         if (Int32.TryParse(idText, out _originalItemId))
  37.         {
  38.             var itemToEdit = ((App)(Application.Current)).CurrentViewModel.TestDataItems.FirstOrDefault(x => x.Id == _originalItemId);
  39.             _itemBeingEdited = new TestData();
  40.             itemToEdit.CopyTo(_itemBeingEdited);
  41.         }
  42.     }
  43.     DataContext = _itemBeingEdited;
  44. }

Hopefully, if anyone else is seeing the same issue, this can shed some light on the problem and present some possible solutions.  The DatePicker and TimePicker controls are convenient and visually appealing approaches to presenting the data they represent in a touch-friendly manner.  However, to be used effectively, it is important to understand their nature as separate pages, despite any efforts they may make to masquerade as something else.