A recent network “hiccup” posed a bit of a challenge to a demo that was built around showing how the Windows Azure Toolkit for Windows Phone (WATWP) NuGet packages make it easy to add Windows Azure cloud features to a Windows Phone 7 application.  So how do you access NuGet content when a network connection isn’t available?  What if you want to exert some management over the updates that are exposed to the developers in your enterprise, including exposing often-used or internal-use assets?

It turns out that NuGet offers some functionality that addresses these scenarios.  In addition to supporting the ability to set up your own package server (also known as Creating Remote Feeds in the NuGet documentation), there is the ability to consume packages collected in a directory – either a network share or a local file-system folder.  This is illustrated in the NuGet documentation under the subtopic "Creating Local Feeds” within the “Hosting Your Own NuGet Feeds” topic.

Populating a File-System Based Package Store

Any folder that contains NuGet .nupkg files can be set to be as a file-system based package server.  From my own use, folders that contain subfolders with .nupkg files will also work, allowing for organization and hierarchy.  If you already have a Visual Studio solution that has references to NuGet packages, moving these packages into such a local package store can be quite simple (especially for demos!)  Just locate the “packages” folder that is created when the NuGet packages are added

image

The entire package folder is not required, since the nupkg files are really Zip files that contain all of the necessary contents.  Search for files that end with the .nupkg extension. 

SNAGHTML9fbf7a

Simply copy all of these files into the folder you are using for your file-system based package store.  Note that a wider set of packages is available in your local package cache, which is normally maintained in <UserFolder>\AppData\Local\NuGet\Cache, and can be accessed from Visual Studio via Tools-Library Package Manager-Package Manager Settings, and click the “Browse” button in the General section of the Package Manager settings node.

Using File-Based Package Stores

To tell Visual Studio to consume file-based package stores, bring up the settings dialog (via Tools-Library Package Manager-Package Manager Settings or through the other accessors in Visual Studio) and select the Package Sources section of the Package Manager settings node.  Provide a name and type in the path or browse to the package location and click the Add button.  Note that the elements in the Available Package Sources list are shown in a check-list-box – they can be enabled or disabled.  Elements in the list can also be reordered in order to determine the precedence in which the sources are searched for matching packages.

SNAGHTMLab5b5b

When adding NuGet package references to your project in Visual Studio via the Manage NuGet Packages dialog, note that the newly named source now appears within the “Online” package listing section. 

SNAGHTMLb09c32

The new source is also available as a pulldown option in the Package Manager Console window.

SNAGHTMLb430e2

As I’ve been digging into NuGet more lately, I’ve been quite impressed by the functionality it exposes.  There’s much more to it than just a right-click menu item and a dialog box  that adds and updates project assembly references.  Some of my current favorites include managing package references at the solution level and visualizing NuGet package chains.  Be sure to check out the NuGet docs in case you have yet to discover your favorite.

Many thanks to the attendees of my presentation tonight covering Developing Cloud Enabled Windows Phone Applications with Windows Azure.  I apologize once again for the technical network-related gremlins that decided to attack us tonight…hopefully the workaround covered the necessary ground and everyone was able to see the concepts I was trying to show.

As promised, I have posted the content for the presentation here.  This includes the slide deck with the various resource links, as well as the final project.  As I mentioned, I have “sanitized” the configuration of the project to omit my specific Access Control (ACS) settings.  This involved changing the AccessControlResources.xaml file in the phone project and the Web.config file in the web role project.  Look for the text [your-xxx-here] for where to substitute your own ACS information.

Because the network issues prevented us from accessing the NuGet site or repository, I wanted to be sure to list the packages that were used in these projects:

Phone.Storage Adds support in the phone project to access Azure Storage.
WindowsAzure.Storage.Proxy.AccessControl Adds support in the server-side MVC3 based web role to field secured storage requests using ACS to generate the authentication token
Phone.Storage.AccessControl Adds support in the phone project for interacting with ACS-secured storage, including a login page with the ACS-aware login control.
WindowsAzure.Notifications Adds support in the server-side MVC3 based web role to handle registration & storage for Push Notification endpoints
Phone.Notifications.BasePage Adds support in the phone project (including a UI page) for enabling notifications in the application and registering with server-side push notification endpoint.
MPNSRecipe Adds the MPNS Recipe, used in the worker role project.

I would like to thank the organizers and attendees of the recent 16th (wow!) Boston Code Camp where I did a talk on Developing Cloud-Enabled Windows Phone Applications with Windows Azure – and special thanks to everyone who stuck it out once the snow started falling in order to catch my talk.  Obviously, it took longer than expected to get this content posted – Nashua got hit especially hard by the storm, including a 75% city-wide power outage the day following the Code Camp event, along with accompanying telecom and even cellular outages.  I am happy to say that I finally got my power turned back on mid-week, and am slowly but surely digging out of the mountain of backlog that piled up during the multi-day outage.

The content can be found here.  Because I demoed ACS, some of the items that are placed in the project would normally reference my “real” Azure account…they have been removed and replaced with the phrase “YOUR CONTENT HERE.”  You will need to replace these values with your own from the Azure ACS management portal in order to be able to run the provided code.  Also, in order to use the Azure Emulator, be sure to run Visual Studio in Admin mode when working with this project.

I had a great time talking about the Windows Azure Toolkit for Windows Phone at the Windows Phone Camp event in Cambridge, MA earlier today.  I have posted the slide deck here for those who are interested in getting at the web links it contains.

If you missed the event and/or are interested in other Windows Phone Camp events, more information is available here.

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.

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.

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.

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

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.)

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. 

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.

I have uploaded the content from my talks at yesterday’s (5/7/2011) New England Code Camp 15.  I had two talks – Introduction to Windows Phone 7 Development with Silverlight and Advanced Windows Phone 7 Development with Silverlight.  The content for my first talk can be found here, and the content for the second talk can be found here.  The content includes:

  • Presentation slides, which include the reference links I mentioned during the talk.
  • The sample code.  In the second presentation I discussed the Bing Maps control.  I have removed my Map Key and replaced it with the text “YOUR_KEY_HERE.”  To remove the licensing warning that appears when running the project, be sure to get an application key from the Bing Maps Developer Portal and replace the temporary text.

After having done various phone talks over the past year, I decided I needed to overhaul the content prior to this presentation.  This was done both in order to relate the contents of the presentation to something that more closely resembled an actual app, as well as in anticipation of including the upcoming “Mango” content.  I think the presentation got closer on those fronts, but it still needs some tuning (especially the first half, which ran a bit long…my apologies to the attendees for having to rush through some of the material.)

I have also discovered an interesting defect in the application that occurred after adding the code to handle saving page-state when the app is tombstoned.  What happens is that the closing of the DatePicker control (from the Silverlight for Windows Phone Toolkit) sets the value of the property before an OnNavigatedTo event is called, which resets the value to what was serialized when the control first appears.  The net result is that the DatePicker control ceases to change the date.  I included a quick fix for this in the code published above, and will be taking a deeper look at this control in the coming days, with a more thorough post to follow.

While I am actively working on adding new functionality to the LightTouch library (such as adding the Pinch Gesture to bring parity with the GestureListener for Windows Phone from the Silverlight for Windows Phone Toolkit) for an upcoming release, a couple of issues came to light that made adding a new release appropriate.  As the title of this post suggests, these issues relate to support for touch in Popups (especially ChildWindow controls) and for controls where different layers of the control’s visual tree make use of different behaviors.

Support for Popups / Child Windows

At the heart of LightTouch is the Manipulation2DBehavior.  Much of the functionality behind this behavior is discussed here.  One of the basic methods’ responsibilities is to determine, based on the coordinates of the touch event, what controls are under that point and which of those controls have the Manipulation2DBehavior attached.  To do this lookup, the VisualTreeHelper.FindElementsInHostCoordinates function is used, with Application.Current.RootVisual supplied for the relative UIElement.  This is where difficulty with popups occurred.  Popup controls exist outside of the Visual Tree of the application’s RootVisual.  This can be seen in the following UI, with its Visual Tree as reported by Silverlight Spy.  Note how the Popup control appears as a sibling to the MainPage element.

image

image

So in order to locate the controls with behaviors in the popup, we have to use the Popup as the relative UIElement for the call to VisualTreeHelper.FindElementsInHostCoordinates.  Now to find the popup in the Visual Tree…this can be accomplished with the VisualTreeHelper.GetOpenPopups call.  Unfortunately, this call does not document how the list is populated relative to the Z-order of the ChildWindow (in case multiple ChildWindows are being displayed, issues of UI-propriety with this approach notwithstanding.)  Empirically, it seems that the topmost child window (if present) is the first in the list, so if any ChildWindows are being shown, we locate the first one in the list, and use it as the argument to FindElementsInHostCoordinates.  From there on, things progress as they had previously.

Supporting “Layers”

Shrek: “NO!  Layers.  Onions have layers.  Ogres have layers.   Onions have layers.  You get it?  We both have layers”
Donkey: “Oh, you both have layers.  Oh.  You know, not everybody likes onions.  What about cake?  Everybody loves cake!”
- Shrek (2001)

So what do I mean about layers?  In this case, I am referring to a situation where multiple related controls under a given point in a visual tree have Manipulation Behaviors attached.  An example would be a ListBox control with the ListBoxTouchScrollBehavior attached, and the underlying data template for the items in the list box having a GestureListener attached with a handler for a DoubleTap event.  The original implementation stopped at the first matching behavior, resulting in the ListBox scrolling, but ignoring the DoubleTap event.  The new implementation now identifies and processes all Manipulations under the given touch point.  This is similar to a Bubbling event, with a couple of key differences.  First, there is no notion of “handled.”  Second, the relationships do not have to exist in common branches of the same visual tree.

Available for Download

The latest code is up on CodePlex and the Alpha-2 release has been built based on these changes, which can be downloaded here.  I hope people find it helpful.

I have uploaded the content from my Introduction to Windows Phone 7 Development with Silverlight talk at the New Hampshire .Net Seacoast User Group meeting last night in Portsmouth. The content can be found here, and includes:

  • Presentation slides, which include the reference links I mentioned during the talk.
  • The sample code, broken into 2 projects. Because the Notification Services portion of the talk adds extra projects to the solution ad is a little more complex to build and launch, that portion has been broken out into its own separate zip file.

For the Notification Services portion of the demo, the web project should be launched first, followed by the phone project (since the phone app calls the web site to register its URL for receiving notifications.) If the solution is run with the web project set as the default start project, the application bits do get deployed to the phone, but the debugger is not hooked up (unless multiple startup projects are used.) If debugging of the phone app is desired, it can be achieved by right clicking on the phone project and selecting Debug / Start New Instance. Also, this time the Notification Services demo includes the Push Notification Server-Side Helper recipe.

As usual, I have “sanitized” the uploaded code content by removing my personal Bing Maps application key. For information on how to obtain your own map key, please check out the Bing Maps Developer Portal.

I have also added a project that  shows the technique for “immediately” updating the application’s tile via a temporary Notification Services endpoint.  This is based on the code first presented here

The posted Slide Deck includes the slides that call out new content in the upcoming “Mango” release of WP7, and I have edited one slide to include one IMPORTANT new addition to the phone SDK that I forgot to previously include – support for Sockets.

Many thanks to Pat Tormey for inviting me to be the inaugural speaker for this new user group, as well as to Mark Mullin and Global Relief Technologies for providing a great site.  Also many thanks are deserved by the attendees, who asked some of the best questions I have gotten since I started doing these talks.

As is often the case when big events happen, sometimes some important announcements can get overlooked and/or overshadowed.  Mix 2011 certainly featured big news, including Silverlight 5 Beta, the Windows Phone 7.5 features, IE10, and the latest in the MVC framework.  However, in all of the hoopla, the release of the SP1 refresh of the Microsoft Visual Studio Async CTP SP1 Refresh, as well as some of the important changes, may have gone unnoticed.

There are a few important things to note regarding the Async CTP Refresh:

  • It includes an “As-Is” Go-Live license for use in production environments (albeit with some stern warnings about why you should really consider NOT using it in production code.)
  • It includes support for .Net, Silverlight 4, and Windows Phone 7.0.

Let me restate that last point.  The Async CTP works with Windows Phone 7 today.  No need to wait for the Mango update.

Now Just “await” a Minute…

As a CTP, and with the “As Is” license, there is no guarantee that this will eventually make it into the framework, and even if it does, it may take a very different form.  That being said, it is a great opportunity to see where things are headed and to offer feedback to the development team as to how to best shape this functionality to be as useful as it can be. 

That’s Nice.  How Long do I have to “await” to See Some Code?

So what do the Async tools bring to the table?  Among other things, it allows asynchronous code to be written without the “disruption” that currently occurs when that is being done today.  While a full discussion of asynchrony and the problems it solves and the new ones it presents are beyond the scope of this discussion, some brief coverage is merited.  Writing synchronous code today follows the pattern of “do something, wait for it to finish, then proceed.”  Altering this to be asynchronous (often) changes the pattern either the Asynchronous Programming Model/APM (“Call BeginXXX to start the operation, then EndXXX to wait for it to be completed”) or to the Event-Asynchronous Pattern/EAP (“start doing something, and raise an event that I am listening for when you are done.”)  When the completion of one asynchronous operation needs to trigger another one, code can get complicated and messy.  This situation is particularly apparent to those who use Silverlight and the related Silverlight for Windows Phone, as all I/O operations in Silverlight are inherently asynchronous.  The Async CTP brings a third model – the Task-based Asynchronous Pattern/TAP. 

The TAP model features the use of the async and await keywords to allow asynchronous code to be written in a much more linear fashion.  Under the covers, the compiler will generate all of the necessary “goo”, allowing the development to focus on the problem at a higher level.  The following code may help to visualize what this all means.

In the code that follows, a WebClient is spun up to return the data at a given URL.  The number of bytes in that data is returned as the result of the function.  This is the synchronous version of the code.

Code Snippet
  1. private void button1_Click(object sender, RoutedEventArgs e)
  2. {
  3.     var count = DoSomething();
  4.     MessageBox.Show(count.ToString());
  5. }
  6.  
  7. private Int32 DoSomething()
  8. {
  9.     var webClient = new WebClient();
  10.     var data = webClient.DownloadString(new Uri("http://www.wintellect.com/Consulting/Consultants/John-Garland"));
  11.     var results = data.Length;
  12.     return results;
  13. }

Note that this code blocks the UI when called, and cannot be used in Silverlight or Silverlight for Windows Phone applications.  So what if you don’t want to block the UI while retrieving the information (or better yet, what if you cannot, as is the case with Silverlight?)  Bring in asynchrony, but notice how it changes the nature of the function.  Where the desire had been to call a function to retrieve a result, now the function is called to eventually signal a response, which must be subscribed to by the calling code.

Code Snippet
  1. private void DoSomethingEAP()
  2. {
  3.     var webClient = new WebClient();
  4.     webClient.DownloadDataCompleted += HandleWebClientDownloadDataCompleted;
  5.     webClient.DownloadStringAsync(new Uri("http://www.wintellect.com/Consulting/Consultants/John-Garland"));
  6. }
  7.  
  8. private void HandleWebClientDownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e)
  9. {
  10.     var data = e.Result.Length;
  11.     MessageBox.Show(data.ToString());
  12. }

This is somewhat compressed and contained when inline lambda expressions are brought to bear, but the fundamental problem still exists.  The function has been modified because of its asynchronous implementation. 

Code Snippet
  1. private void DoSomethingEAPLambda()
  2. {
  3.     var webClient = new WebClient();
  4.     webClient.DownloadDataCompleted += (o, e) =>
  5.     {
  6.         var data = e.Result.Length;
  7.         MessageBox.Show(data.ToString());
  8.     };
  9.     webClient.DownloadStringAsync(new Uri("http://www.wintellect.com/Consulting/Consultants/John-Garland"));
  10. }

Now lets see how using the Async tools change things. 

Code Snippet
  1. private async void button1_Click(object sender, RoutedEventArgs e)
  2. {
  3.     var count = await DoSomethingAsync();
  4.     MessageBox.Show(count.ToString());
  5. }
  6.  
  7. private async Task<Int32> DoSomethingAsync()
  8. {
  9.     var webClient = new WebClient();
  10.     var data = await webClient.DownloadStringTaskAsync(new Uri("http://www.wintellect.com/Consulting/Consultants/John-Garland"));
  11.     var results = data.Length;
  12.     return results;
  13. }

Note that the functions now much more closely resemble the initial synchronous version. 

I’m Tired of “awaiting”.  Get Me the Bits.

This was just a light overview.  There are many other combinations and applications for the TAP.  Hopefully, this was enough to pique some curiosity.  If interested, the download for the Microsoft Visual Studio Async CTP SP1 Refresh is available at http://msdn.microsoft.com/en-us/vstudio/async.  This includes documentation, samples, and walkthroughs.  The tools require Visual Studio 2010 SP1.  Check out Eric Lippert’s announcement of the release (and additional links) at http://blogs.msdn.com/b/ericlippert/archive/2011/04/13/refreshing-the-async-ctp.aspx.

More Posts Next page »