I’d managed to get my Windows Phone upgraded to the ‘Mango’ developer beta 2 release and so I thought I’d revisit my amazing ContactShare application that I’d built against the RTM version of Windows Phone.
Firstly, I thought it’d be good to do a quick review and see how well my application had been doing on marketplace because I’ve been thinking it might buy me one of these;
I popped into the App Hub and checked out the data;
Wow – 340 downloads and 0 crashes! I count at least the latter part as a major success. Then again, maybe the people who downloaded it didn’t actually run the app
That said, I guess I might have to scale back my ambitions to one of these;
Regardless, I thought I’d crack open the source code and see how what sort of changes I might be able to make to the app if it’s going to run on ‘Mango’
Initial Steps
Initially, I just opened up the existing project and made sure that it ran under the current bits that I’ve got installed because I’ve moved to a different development laptop and I’ve updated the Windows Phone SDK since I last opened this particular project.
All was good except I noticed that a particular “Store Changes” button on my UI had lost its content;
I instantly thought that I’d spotted some kind of ‘Mango’ bug but, in reality, when I go and take a look at the XAML I notice that at some point I’ve lost the content for that button – serves me right for not having this under source control.
With that minor issue “resolved”, I go and visit the properties page for my application and move it from targeting Windows Phone 7.0 to 7.1;
I must admit that I smiled when this dialog sprung up;
because my natural paranoia meant that I had already made a backup copy of the project before I even opened it up in Visual Studio.
With that change made, I ran up the app and noticed that I hit an initial snag.
In my app, I’d made use of a technique a little like this below in order to run some code when my UI was loaded. The code is on my ViewModel rather than my view and hence using the binding to an ICommand;
That all seemed to work fine under the previous RTM release but I was finding that the EventTrigger here simply wasn’t firing and my LoadedCommand wasn’t running as the UI was loaded.
Now, the InvokeDataCommand class I’d used there was from the Expression Blend Samples and it was no longer working on ‘Mango’.
I had to do a little bit of head-scratching to remember why I’d used this sample in the first place. I think ( from my own post ) that in the pre-‘Mango’ release System.Windows.Interactivity did contain the InvokeCommandAction class but it wasn’t so useful because it didn’t have a Command property of type ICommand on it that was bindable.
Because of that, I’d used the sample.
Now, in ‘Mango’ the built-in InvokeCommandAction class does have a bindable Command property on it so I replaced the use of the sample class with this class and all seemed to be good.
As an aside, I suspect this is because RTM was Silverlight 3 whereas ‘Mango’ is Silverlight 4. In Silverlight 3 you could only have a dependency property of a FrameworkElement as the target of a binding which would have made it pretty tricky to implement that Command property. In Silverlight 4, you can have a dependency property of a DependencyObject as the target of a binding which means that InvokeCommandAction can now have a proper Command property.
With that problem addressed, things seemed to work reasonably well so I wondered if there were a few ‘Mango’ changes I could then make to the app.
I’ll come back to this notion of using Loaded events though because I was doing something wrong and I ended up ripping all this kind of code out of the app anyway once I’d got over my disgust at the rubbish code I’d written
Choosing Contacts
In the previous iteration of the application, I had a screen where you had to enter your FirstName, LastName, Email Address, Phone and then the app creates a QR Code representing that data.
It’s a bit of a pain having to enter that data when often you have a contact card for yourself stored in your phone.
However, prior to ‘Mango’ the only way to get to those 4 pieces of data would have to raise a chooser task multiple times asking you to select each piece of data separately. That’s worse than typing it in.
With ‘Mango’ this changes and so what I chose to do here is offer a new piece of UI to “load data from contacts”;
Now, as far as I know, I’m still limited to using one of the choosers (e.g. Phone, Email, etc.) and so I chose to use the PhoneNumberChooserTask and then when it returns a phone number I used the Contacts class in order to do an asynchronous search to find the full contact details from that phone number. I figure the phone number is likely to be “relatively” unique – the code looks a bit like this;
void OnContactPhoneNumberChosen(object data) { string phoneNumber = (string)data; if (!string.IsNullOrEmpty(phoneNumber)) { Contacts contacts = new Contacts(); contacts.SearchCompleted += (s, e) => { if (e.Results != null) { this.BusyVisibility = Visibility.Collapsed; Contact contact = e.Results.First(); if (contact.CompleteName != null) { this.FirstName = contact.CompleteName.FirstName; this.LastName = contact.CompleteName.LastName; } if (contact.EmailAddresses != null) { ContactEmailAddress email = contact.EmailAddresses.FirstOrDefault(); if (email != null) { this.EmailAddress = email.EmailAddress; } } this.PhoneNumber = phoneNumber; } }; this.BusyVisibility = Visibility.Visible; contacts.SearchAsync(phoneNumber, FilterKind.PhoneNumber, null); } }
and that seems to work pretty well;
and it’s definitely an improvement over typing details manually if you happen to have a contact for yourself in your phone.
State Management and LifeCycle Changes
Windows Phone ‘Mango’ has fast application switching as a supplement to the tombstoning process that existed in the Windows Phone RTM.
This leads to a new state in the life-cycle diagram taken here from MSDN;
I believe that the Dormant state above is a new state that exists in ‘Mango’. Previously if a user ran my app and then navigated “forwards” from it, the app would have been Tombstoned and would have to restore state as the user navigated “back” to the app instance.
However, in ‘Mango’ if a user navigates “forward” from my app then the app will be made Dormant and if they navigate back the app shouldn’t have to restore state as it’s in memory already. Only if the app has to be Tombstoned in the meantime will I have to restore state and that only happens if the OS needs to reclaim resources in the meantime.
Now, my app is really simple and only displays a single page with a single Pivot control on it.
Because of this, I assumed that these changes would have zero impact on me. I was wrong although, to be fair, it looks like it was my fault that I got impacted.
When I first wrote this app, I made an assumption that my page (and the controls on it) would be loaded every time someone navigated to the app. I hooked up ( using triggers and commands) code that would run in my ViewModels when the Loaded event occurred on certain UserControls.
This worked fine prior to ‘Mango’ as navigating to my application always caused the UI to be (re)created and so the Loaded events would fire.
On ‘Mango’, this doesn’t work fine. The UI is not necessarily re-created when I navigate from the app and then back again because the app may have stayed Dormant and the UI never got torn down and so my Loaded code doesn’t necessarily run.
‘Mango’s changes here then highlighted problems that I was “getting away with” in my previous implementation and so I changed the way I was doing things to rely more on the OnNavigatedTo events.(as described here).
One thing I struggled with while trying to debug this code. I found it hard to test whether my changed tombstoning code was now working because it’s hard (impossible?) to force an application switch to cause tombstoning until I came across the new “force tombstoning” option on the debugger settings;
which made life a lot easier and so at least that code can be (manually) tested under the debugger.
Saving Contacts
My app tries to decipher a QRCode containing MECard data containing [First Name, Last Name, Email, Phone].
Unfortunately, Windows Phone prior to ‘Mango’ does not have a great experience for saving all of that information into a contact.
Instead, it offers two separate tasks which can either save the email or the phone but not both.
Consequently, my previous UI had to offer two separate save options. One for the email and one for the phone number which was a bit painful to use.
‘Mango’ offers a new SaveContactTask which allows for saving all the information and so I updated my code to make use of that rather than offering 2 menu options. It’s pretty easy from the point of view of code and the user experience is much nicer.
Removing Most of the App 
My app originally had 2 functions;
- Turn your contact details into a QRCode for someone else to photograph and import into your phone.
- Turn a photograph of a QRCode into contact details for you to save on your phone in order that you can do (1).
Function (2) is pretty much redundant on Windows Phone ‘Mango’ because the phone can already do this – there’s a built-in experience around “visual search” where you can point the camera at a QRCode and then save it as a contact.
So…half my app is redundant but I left the functionality in there anyway.
Changing the Tile
One of the things that I wanted to do in the original version of the application was to have the application’s tile be the QRCode that stores your contact details so you didn’t have to run the app to get to the QRCode if you’d pinned it to your start screen.
As far as I know, it wasn’t possible to do this unless the image in question was out on the web somewhere and my QRCode image is stored in isolated storage on the phone and I didn’t want to have to rely on a data connection for this app at all.
In ‘Mango’, updating the tile is perfectly simple and so I’ve changed the app so that once you have entered some contact details to create a QRCode it will update its tile to be that QRCode as in;
with the idea being that if you’ve pinned the app to the start screen then the QRCode is immediately available (if a little small).
This was pretty easy to do. I already stored my QRCode in isolated storage but for the shell to be able to get to it I changed the location to be;
Shared/ShellContent/barcode.jpg
where the barcode.jpg bit is not relevant but the rest is. With that in place, I can then change the application’s tile;
StandardTileData tileData = new StandardTileData() { BackgroundImage = new Uri("isostore:" + barcodeFile) }; if (ShellTile.ActiveTiles.Count() > 0) { ShellTile.ActiveTiles.First().Update(tileData); }
where I prepend isostore: to the front of that previous file path in order to form a Uri and then change the application’s tile which seems to work out fine.
Extending the Pictures Hub
One of the things that I’d implemented in the app was to plug it into the pictures hub on the phone so that a user could select a picture that they’d taken and then launch straight into my app from that picture.
This has changed in Windows Phone ‘Mango’ (details here http://msdn.microsoft.com/en-us/library/hh202966(v=VS.92).aspx ) and so I found that I had to rework this a little as I had an extras.xml file which is no longer needed.
In the new ‘Mango’ world, you can choose to extend either or all of the;
- Picture Viewer
- Pictures Hub
- Share Picker
and it seemed to make most sense to me to extend the Picture Viewer although I’m not sure that I meet all of the requirements for this specified here (http://msdn.microsoft.com/en-us/library/hh184838(v=VS.92).aspx) under the title of “Applications That Extend The Picture Viewer” so I’ll have to see what my submission to the marketplace comes back with.
In terms of doing this, there’s an Extensions section to add to the application manifest;
<Extensions> <Extension ExtensionName="Photos_Extra_Viewer" ConsumerID="{5B04B775-356B-4AA0-AAF8-6491FFEA5632}" TaskID="_default" /> </Extensions>
That seemed to work fine in that my app showed up in the list of apps presented to the user when they are viewing a picture in the pictures hub.
Other than that, the experience of extending the hub doesn’t seem to have changed in that you still get passed a query string which has a token on it that you can use to retrieve the picture in question.
One slight “gotchya” with this though that I encountered both on this port and on the previous initial implementation is that my app gets into a situation like this;
- The user selects a picture in the pictures viewer and sends it to my app.
- My app runs with a NavigationContext which has a query string that can be used in order to grab the picture.
- My app grabs the picture and starts to try and decipher the QRCode in that picture.
- User presses the start button to navigate to another app.
- User presses the back button back to my app.
- The NavigationContext is still there with the query string.
- My app grabs the picture (again!) and starts to try and decipher the QRCode in that picture.
It’s step 6 that surprised me when I first saw it. To avoid (7) happening, I store explicit state to note that we’ve already attempted to process that picture otherwise we end up in a bit of a loop which the user probably wouldn’t expect or understand.
Marketplace
My next step will be to re-submit to the marketplace now I’ve got a ‘Mango’ version of the application taking care to note that there are implications of this which Mike has blogged about here.
All in all, it was fun to revisit this code and update it for ‘Mango’ and it’s clear even in a simple app like this one that there are many improvements coming through from the underlying platform. I’ve also found ‘Mango’ to be really stable and usable on my phone in regular use – no going back for me on this one