Saturday, March 3, 2012

Windows 8 Consumer Preview & Visual Studio 2011

 

Windows 8 Beta is here. And it’s fantastic. I’m not just saying it because I’m a Microsoftie, or because I’m getting paid for that, or anything like that. This is (so far) my honest sincere opinion. Why, may you ask ? Just play with it for a little while and you’ll know. The Start menu is just beautiful, feels like a smartphone with no capacity restrictions. I really like the corner gestures : lower left for the start screen, upper left for last open app AND list of all open apps, upper and lower right for bringing up the charms. And I love the new ability to close an app by grabbing the top “edge” of it and literally bringing it down through the bottom of the screen. Feels so good to do that. And the crazy thing is, it all works just as well with touch AND mouse & keyboard. In short, love it.

image

Now for the serious stuff : I have quite a few apps I developed on the Developer Preview version. Bad news : so much has changed in Windows (winRT) that they just no longer run in the new version. Just try to open an devprev app with VS 11 consprev : total fail!

So, let’s roll up our sleeves and get to work, there’s a lot of stuff to catch up with to understand the breaking changes. It’s all listed in this document, have fun reading it… As far as I’m concerned, I decided to read it on an as-needed basis. So where do I start in migrating my apps ? I have this sample app I wrote using the Grid Application VS template in the old world. Tried to open it in the new vs, no way. So I followed the basic guideline that says, create a new project and then '”import” your code. I created a project using the new Grid metro style app template (C# XAML) :

image

That created a GroupedItemsPage, a GroupDetailPage, and an ItemDetailPage for me. New thing : these pages inherit from a base LayoutAwarePage which handles the layout change events associated with the visual states such as Filled vs Snap or Portrait vs Landscape. Also has some infrastructure code to facilitate data binding in our custom pages. Anyway, if you try to bring in a page from an existing devprev app, build will fail as a lot of APIs have changed. For example, classes that have the word ‘Layout’ in their names have been renamed to use ‘View’ instead, so ApplicationLayout has become ApplicationView. That’s just an example. Since the old pages contained the layout change code, it’s really a pain to try to update them. So the best approach is to recreate the page, and bring in the custom XAML that you’ve created to build the UI. Doing so, it wasn’t too bad porting the app – of course I’m talking about a simple app using the Grid template and some data binding.

Speaking of the devil, using data binding is a bit different as well. If you look at the new Grid project template, the code-behind files use an object called DefaultViewModel. If yo examine the base LayoutAwarePage, you’ll see that DefaultViewModel refers to an ObservableDictionary<string,object>. What the heck is that, I hear you ask ? It’s just a convenient way of storing a simple view model. Say you have data in the form of a list of groups of widgets, and you want the grouped page to show the groups, then the group details page to show the content of a group, that is a sub-list of widgets, and then a detail page that shows data for a specific widget.  You can store the list of groups in the dictionary under a string such as “WidgetGroups”. Then in your XAML you can define a CollectionViewSource pointing to your list like this :

   1: <CollectionViewSource
   2:     Source="{Binding WidgetGroups}"
   3:     IsSourceGrouped="true"
   4:     ItemsPath="Widgets"/>




‘Widgets’ is the name of the list within a group, so WidgetGroups is a list of groups that each contains a list of Widgets. Now where does that all get set, you scream ? It all starts in app.xaml in the OnLaunched event, where this code is called :



   1: rootFrame.Navigate(typeof(GroupedItemsPage),myWidgetGroups);

As you guessed, this will bring up the GroupedItemsPage – notice the Frame.Navigate() method has changed, it now accepts a type as the first param – and pass to it the group list. Now, in the GroupedItemsPage itself, in the OnNavigatedTo() method you do something like this :



   1: protected override void OnNavigatedTo(NavigationEventArgs e)
   2: {
   3:     this.DefaultViewModel["WidgetGroups"] = e.Parameter;            
   4: }



Where e.Parameter is the myWidgetGroups object you set in the Navigate call. It’s now stored in the DefaultViewModel dictionary under the “WidgetGroups” key, and the dictionary is the datacontext for the page, so you’re all set!


You do the same to pass data to your other pages : when something is selected for example, you call Navigate(typeof(myotherpagetype), theSelectedStuff) and in the other page, you retrieve it in the OnNavigatedTo() method and add it to the DefaultViewModel dictionary under a different key. So what’s the purpose of this new Dictionary ? Being an ObservableDictionary, it has the capability of notifying the UI when its contents are updated. So there you have it, a new INotifyCollectionChanged copycat, and a super convenient one too.


So this was a quick example of how to port a metro app written in XAML under devprev to the new consprev version. I’ll be doing quite a bit of that in the days to come, as I’m refreshing a couple of new courses on win8 Metro, so I’ll keep you posted!

Thursday, July 28, 2011

Push notifications in Windows Phone 7.5 (Mango) -part 2

This post follows up from PART 1. So far, we’ve created our custom web service and registered our phone app with the service. Now let’s implement the main operation in our web service.




Implementing PushToSubscribedPhones

This operation will be invoked from an external app that needs to have push notifications send out to registered devices. Here we need to create a web request, and depending on the type of notification we want to send out, create the payload in accordance with the required schema for that type. Then we send the request out to MPNS to each registered device, through the channelUri we stored for each device in the subscribedPhones dictionary :
public void PushToSubscribedPhones(NotificationData data)
{
foreach (var entry in subscribedPhones)
{
var uri = entry.Value;
byte[] payload;
 
var request = (HttpWebRequest)WebRequest.Create(uri);
request.Method = "POST";
request.ContentType = "text/xml";
 
if (data.PushType == "toast")
{
payload = GetToastPayload(data.Title, data.JobId);
request.Headers.Add("X-WindowsPhone-Target", "toast");
request.Headers.Add("X-NotificationClass", "2");
}
 
else if (data.PushType == "tile")
{
payload = GetTilePayload(data);
 
request.Headers.Add("X-WindowsPhone-Target", "token");
request.Headers.Add("X-NotificationClass", "1");
}
 
else //raw
{
payload = Encoding.UTF8.GetBytes(myMessageData);
request.Headers.Add("X-NotificationClass", "3");
}
 
request.ContentLength = payload.Length;
 
using (Stream requestStream = request.GetRequestStream())
{
requestStream.Write(payload, 0, payload.Length);
}
 
var response = (HttpWebResponse)request.GetResponse();
}
}
}

Here’s an example of the GetTilePayload method, that generates the message to be sent within a tile notification :


private byte[] GetTilePayload(NotificationData data)
{
string payload = string.Format(
"<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<wp:Notification xmlns:wp=\"WPNotification\">" +
"<wp:Tile Id=\"/Views/JobDetailsView.xaml?id=" + data.JobId + "\">") +
"<wp:BackgroundImage>{2}</wp:BackgroundImage>" +
"<wp:Count>{1}</wp:Count>" +
"<wp:Title>{0}</wp:Title>" +
"<wp:BackBackgroundImage>{3}</wp:BackBackgroundImage>" +
"<wp:BackTitle>{4}</wp:BackTitle>" +
"<wp:BackContent>{5}</wp:BackContent>" +
"</wp:Tile> " +
"</wp:Notification>",
text, data.Count, data.TileUri, data.BackTileUri, data.BackTitle, data.BackContent);
 
return Encoding.UTF8.GetBytes(payload);
}

Note a couple things : first, the message’s components are provided by the calling app through the data parameter. Second, many of these elements are actually values that will be set on the properties of the target live tile, both for the front and back side of the tile. And third, notice the Id attribute that identifies the tile targeted by the notification – remember there may be more than one tiles pinned to the phone’s start menu.

When GetResponse() is called in the previous snippet, the notification is actually sent out to MPNS, which sends back a response. Depending on network, device and other factors, MPNS will then send the notification to the registered phones.



Invoke the web service from an external app

Now that your setup is complete, you can have an external caller invoke the operation to send out information to registered devices in the form of either a push, tile or raw notification. For example, within a WPF app you may write :


pushClient.PushToSubscribedPhones(
new NotificationData
{
PushType = "toast",
JobId = job.Id,
DriverId = driverId,
Title = "Job updated : "
});

This uses an instance of the web service client proxy class, which can be generated for you by Visual Studio using the Add Service Reference command. You call the PushSubscribedPhones operation in our service (you may want to do so asynchronously).  You create a NotificationData instance to specify the information you need to pass to the phones in the notification. Note this example sends a Toast, but you can also send a Tile notification and set the properties of the target tile :


var data = new NotificationData
{
PushType = "tile",
JobId = jobId,
Title = "Cancelled",
TileUri = "/Images/TileJobCancel.png",
BackTileUri = "/Images/TileJobCancelBack.png",
Count = 0,
BackTitle = "CANCELLED",
BackContent = "Unpin this job"
};


When the phone app receives the tile notification, any pinned tile will be updated with the values passed in the message.


So we’ve gone briefly through the push notification setup process involving our phone app, a custom service, MPNS, and possibly an external caller. We could also implement the service part in the cloud, as well as the calling app if we chose to.

In a later post, I’ll discuss possible failures and how to handle them.

If you’d like me to cover certain topics, feel free to send a comment.


Happy notifications!

Push notifications in Windows Phone 7.5 (Mango) -part 1

With push notifications, you can have your website or service send messages to an app running on a bunch of phone devices registered to receive the messages. These messages may trigger a toast popup on the phone, update a specific tile, or simply pass some raw data  to the phone app.

Push notifications work by creating a dedicated, one-on-one communication channel between the phone app and the Microsoft Push Notification Service (MPNS). Then, when your service or web app wants to send a notification to the phone, it sends it to the MPNS through a pre-determined URI, and MPNS will forward it to the phone as soon as it can.


image


In Mango, push notifications have gained in robustness. They are now more reliable, efficient, and performant. An example of reliability improvement is the revamped so-called TDET detection mechanism, which is the timeout period on a mobile network after which the data connection to your device is dropped for network efficiency. There is a wide range of mobile network configurations in this regard, which used to cause problems for push notifications delivery – push notification require a persistent channel to exist between MPNS and the device. Mango brings broader network compability in this respect.

As a result of the deep improvements, you now have up to 30 MPNS channels on a single device, vs. 5 previously (I think that was the number). In any case, each app can still have only one MPNS channel.
Here’s the basic process to implement push notifications in your app :

- Create a web app or service to let devices register and to send out notifications to them
- In the phone app, create an MPNS channel and then register the phone with web app
- In the phone app, bind to the channel to receive toast, tile and/or raw notifications
- In the web app, implement the operation to create and send notifications to the devices
- From an external client, call the web app’s send method, passing notification data to it

Let's look at each of these steps.




Create the web app or service
In your solution, create a new WCF application. In your service definition interface you can define 2 methods, one that phones will call to register with the service, and the other to send notifications to registered devices. For example  :
[ServiceContract]
public interface IMyPushService
{
 
[OperationContract]
void RegisterPhone(int driverId, string channelUri);
 
[OperationContract]
void PushToSubscribedPhones(NotificationData data);
 
}

Note that RegisterPhones takes a unique Id for the device and the URI that the channel URI that the device obtained from MPNS, as we’ll see. Its implementation can be as simple as storing the device’s channel Uri in a static dictionary :


static Dictionary<int, Uri> subscribedPhones = new Dictionary<int, Uri>();
 
public void RegisterPhone(int driverId, string channelUri)
{
subscribedPhones[driverId] = new Uri(channelUri, UriKind.Absolute);
}

PushToSubscribedPhones accepts a custom object that will contain the data we need to include in our notification messages. So NotificationData can be any class that exposes properties we need to send that data back and forth. Of course it needs to be decorated with the [DataContract] attribute.


[DataContract]
public class NotificationData
{
[DataMember] public string PushType;
[DataMember] public string Title;
[DataMember] public int Count;
[DataMember] public string TileUri;
[DataMember] public string BackTitle { get; set; }
[DataMember] public string BackContent { get; set; }
... }

We’ll come back to PushToSubscribedPhones in a moment.


Register the phone app with MPNS

When your phone application starts it needs to establish a communication channel with MPNS. It looks for an existing one from a previous execution (channels are persisted on the phone), and if none is found, it creates one  :


channel = HttpNotificationChannel.Find(channelName);
if (channel == null)
{
channel = new HttpNotificationChannel(channelName);
}

You hook up a handler for the ChannelUriUpdated event, and in the handler you can retrieve the channelUri asynchronously returned by MPNS and then register with the custom service through the RegisterPhone operation :


channel.ChannelUriUpdated += OnChannelUriUpdated;
 
void OnChannelUriUpdated(object sender, NotificationChannelUriEventArgs e)
{
pushClient.RegisterPhoneAsync(App.MyDriverId, e.ChannelUri.ToString());
}

Once you’ve hooked up the handler, you can call the Open() method on Channel if the channel is new, which will asynchronously request a channel Uri.

Bind to the channel to receive toast and/or tile notifications

If you want your phone app to receive toast and/or tile notifications, in the above handler you also need to call the BindToShellXXX methods accordingly :


if (!channel.IsShellTileBound)
channel.BindToShellTile();
 
if (!channel.IsShellToastBound)
channel.BindToShellToast();

Note that the channel you create will only be persisted on the device across app instances if you bind to it for toast or tile. If you don’t, it will be destroyed and you’ll need to create a new channel the next time you run the app.

In addition to the ChannelUriUpdated event, you may want to handle the ShellToastNotificationReceived event if you want your app to receive toasts even when the app is running – in which case toasts normally get discarded. You can also handle HttpNotificationReceived if you want your app to receive and handle raw notifications, which are pieces of custom data send through MPNS.

So at this point, we have our web service sketched out and our phone app registered with both MPNS and our service. The next step is to implement the PushToSubscribedPhones() operation in the service. I’m running out of time so I’ll do that in Part2.

Stay tuned !

Part 2 is now live

Saturday, July 16, 2011

Windows Phone 7.5 (Mango) dynamic live tiles

In Mango, an application can have several tiles associated wih it : the primary or “application'” tile, and as many secondary tiles as desired. Secondary tiles have the capability of taking the user to a specific area of the application through an associated deep link, as opposed to the main application page as with the primary tile. This is one example of the new deep linking capability Mango brings.

As in WP7, tiles are pinned or unpinned to the phone’s start menu by the user. All tiles have the ability to display information dynamically, such as a current game score or flight status information. Your application updates the displayed information by setting the tile’s title and count properties, and/or the tile’s background image.

In Mango, tiles are now 2-sided, which means they flip over at regular intervals when pinned. We can now also use the BackTitle, BackContent and BackBackgroundImage properties to display on the flip side.

To create a tile in your app, you first create a StandardTileData object to set the desired properties :
StandardTileData NewTileData = new StandardTileData
{
BackgroundImage = new Uri("/Images/Red.jpg", UriKind.Relative),
Title = "Mary & John",
Count = 12,
BackTitle = "Just married",
BackContent = "Current score : 123",
BackBackgroundImage = new Uri("/Images/Blue.jpg", UriKind.Relative)
};

Then you call the static Create() method on the ShellTile class :

ShellTile.Create(new Uri("/NewlyWeds.xaml?TileID=2&date=Mary And John", UriKind.Relative), NewTileData);
Notice the argument passed to the Create method : When creating a secondary tile, you can specify the launch Uri that the app will receive when started from the tile. You can point the Uri to a specific page deep into the app, or simply use it to pass query string parameters into the app.

Before creating a tile, or if you want to update an existing tile, you may need to check wether the tile already exists and if so, retrieve the existing tile in order to update it. You can use the ActiveTiles collection property of the ShellTile class to do that. ActiveTiles always contains the application’s primary tile as well as any secondary tiles created by the application. To retrieve the application tile, just use FirstOrDefault() :

var apptile = ShellTile.ActiveTiles.FirstOrDefault();


To retrieve a specific secondary tile, you need to use a unique identifier for that tile. You can use the deep link Uri that was passed into the constructor when the tile was created :

DirectUri = "/View/Kite.xaml?id=fuel2011";
ShellTile.Create(new Uri(DirectUri, UriKind.Relative), tileData);

Now to retrieve the tile, use a LINQ query on the ActiveTiles property to test whether NavigationUri contains the unique ID :

var tile = ShellTile.ActiveTiles.SingleOrDefault(
t => t.NavigationUri.ToString().Contains("id=" + ParamId));

Note that I’m not using NavigationUri.Contains(DirectUri). The reason is that the NavigationUri property returns a URL encoded version of the deep link Uri that was passed in the constructor. If you set a breakpoint you’ll see that NavigationUri returns something like ‘file:///View/Kite.xaml%3Fid=fuel2011’. So NavigationUri.Contains(DirectUri) would return false for the tile we’re trying to retrieve.

Once you get ahold of the existing tile, you can easily update its properties :


var data = new StandardTileData
{
Title = "New Fuel 2011!",
Count = 2,
BackgroundImage = new Uri(picpath, UriKind.Relative),
BackContent = "This is the great new updated Fuel!",
BackTitle = "Check it out!",
BackBackgroundImage = new Uri("/Images/tilekiteback.png", UriKind.Relative)
};
 
tile.Update(data);

You can also remote a tile by calling the Delete() method on the tile.

So using ShellTile and StandardTileData, it’s very easy to create and manipulate both primary and secondary tiles in our app. In a later post I’ll discuss updating tiles on a schedule, using both the ShellTileSchedule APIs and background agents.

Happy tiling!