Development, MVVM, Silverlight, WP7

My “Hello World” Windows Phone 7 Application

This entry is part 8 of 8 in the series Windows Phone 7

I’ve done a TON of Windows Phone 7 demos over the past few months, and I get asked all the time for access to download my samples. I’ve been meaning to post this application since I started all of this, but just never got around to it.  SO – here it is… the now Infamous MVVMLight-ified Netflix Catalog Sample!

imageimage

 

This is by no means a comprehensive sample, but it does show some of the neat features of WP7 as well as a sample for how to integrate MVVM Light into your phone applications.  Get the code from my Skydrive:

Development, Silverlight, WP7

InputScopes for Windows Phone 7

This entry is part 6 of 8 in the series Windows Phone 7

I have used Shawn Oster’s excellent InputScopes blog post and accompanying demo in the past when talking about Silverlight and the first revisions of the Windows Phone 7 dev tools, but noticed today when I was prepping for a talk that it no longer seems to work right with the Beta bits.

After a little code spelunking, some dusting and even a little vacuuming, I seem to have arrived at a really nice V2 demo.

Concept

The concept is simple – entering text into Silverlight and Windows Phone (via the SIP) is a customizable experience.  The concept of InputScopes was introduced to allow developers to customize how the keyboard would behave for a given input control (e.g. TextBox).  Not all controls support InputScopes, so make sure you read Shawn’s excellent article to get all the details.

Code changes

I only made a few changes, just to keep it in line with how our Best Practices have evolved.

First, I changed the behavior of the EnumHelper class to use LINQ and removed a whole bunch of code:

public static IEnumerable<string> GetNames(Type enumType)
{
    if (!enumType.IsEnum)
    {
        throw new InvalidOperationException("Specified generic parameter must be an enumeration.");
    }
 
    var query = from inputScope in enumType.GetFields(BindingFlags.Public | BindingFlags.Static)
                orderby inputScope.Name
                select inputScope.Name;
 
    return query;
 
}

Next, I cleaned up MainPage.xaml and replaced the code-behind approach with some element-to-element data binding to wire up the selected InputScope.  I also added a counter at the bottom showing how many InputScope objects are available in WP7.

    <Grid x:Name="LayoutRoot"
          Background="Transparent">
 
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="1*" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <TextBlock x:Name="PageTitle"
                   Text="input scopes"
                   Grid.Row="0"
                   Style="{StaticResource PhoneTextTitle1Style}" />
        <TextBox x:Name="textBox1"
                 FontSize="32"
                 Grid.Row="1"
                 InputScope="{Binding ElementName=listBox1, Path=SelectedItem}" />
        <ListBox x:Name="listBox1"
                 Margin="10"
                 Grid.Row="2"
                 SelectedItem="Default"
                 FontSize="32" />
        <StackPanel Grid.Row="3"
                    Orientation="Horizontal"
                    HorizontalAlignment="Center">
            <TextBlock FontSize="32"
                       Text="{Binding ElementName=listBox1, Path=Items.Count}" />
            <TextBlock FontSize="32"
                       Text=" InputScopes loaded" />
        </StackPanel>
    </Grid>

That way, the only thing left in my code-behind is the initialization of the ItemsSource property of the ListBox (which I could have changed to use MVVM instead, but hey…)

public partial class MainPage : PhoneApplicationPage
{
    // Constructor
    public MainPage()
    {
        InitializeComponent();
        listBox1.ItemsSource = EnumHelper.GetNames<InputScopeNameValue>();
    }
}

Get the bits!

I’ve posted them on my SkyDrive for easy access.  If you’re in Shreveport tonight, you’ll get to see this LIVE at tonight’s Shreveport .NET User Group meeting, albeit for only about 1 minute Winking smile

Development, WP7

Customizing WP7 Push Notification Tiles

This entry is part 5 of 8 in the series Windows Phone 7

Although I had originally hoped to be one of the first, there are LOTs of great articles out now about how to use Push Notifications in Windows Phone 7. Instead of re-hashing information that is already readily available on the internet, this article will instead focus on some of the things that have been left out of those articles.  If you need a refresher on how Push Notifications work, I will refer you to the following excellent articles that show you how to get it done:

My situation seemed really simple – I really liked the idea of being able to publish notifications to my WP7 applications, but didn’t AT ALL like the way they looked when they got there.  As you probably already know from your reading, that the notification system, by default, gives you the ability to customize 3 aspects of a tile – the background image, application title, and a “count”, as illustrated in the picture below:

Each tile is a 173×173 block that contains the three key elements.  My issue was with that little blue circle at the top.  It’s cool how the Outlook, Phone and Text tiles have very big, easy to read information, but I found it more difficult for my eyes to read the small number in the upper-right-hand corner of the tile. Instead, I’d rather have something that looked more awesome, like this:

Untitled

I spoke with some guys from the WP7 dev team, and they confirmed that there is no way to customize the tile layout beyond what it gives you. So that meant, any customization I needed to do would have to be done using dynamically-built graphics… My reasoning is this – the device can only get 3 pieces of information, and the graphics are the most customizable of the bunch. If I take all the information that would normally be sent down as 3 separate data points and combine it into one dynamically-built image, I can make the tile look like whatever I like.

Where to begin…

I started by downloading Yochay’s excellent Windows Phone 7 Training Kit and extracting out his lab on Push Notifications.

This lab is an EXCELLENT primer on Push Notifications in WP7, and I highly recommend that you walk through it before you try doing anything else with Push. His sample got me the boilerplate code I needed to begin my customizations. I was especially happy that he extracted all of the heavy lifting related to the actual Push into a separate assembly that I could start hacking into without fear of messing up the driver or the phone application itself. 

The architecture of the sample is really straightforward – you have a phone application that registers with the Live Notification Services and a WPF-based Driver program that pushes Tile, Toast and Raw updates down to the device.  It seemed like the most straightforward path was to modify the Driver program to somehow send out custom generated background images instead of referencing some existing static ones.  Unfortunately, that’s not how the Push Notification system works.  When you send a notification to the Phone, the phone doesn’t actually receive the image – it receives a URL pointing to the image:

<?xml version="1.0" encoding="utf-8"?>
<wp:Notification xmlns:wp="WPNotification">
  <wp:Tile?>
    <wp:BackgroundImage>/Images/Cloudy.png</wp:BackgroundImage>
    <wp:Count>28</wp:Count>
    <wp:Title>Moscow</wp:Title>
  </wp:Tile>
</wp:Notification>

To accommodate a pull scenario from the device, I was going to need a way for the device to request images based on some parameters.  For that, I’d need a new web site with a custom HTTP handler that built the images I needed based on those parameters – something on the order of this:

<?xml version="1.0" encoding="utf-8"?>
<wp:Notification xmlns:wp="WPNotification">
  <wp:Tile?>
    <wp:BackgroundImage>http://somehost.com/ImageBuilder.ashx?city=Moscow&temperature=28&conditions=Cloudy</wp:BackgroundImage>
    <wp:Count>28</wp:Count>
    <wp:Title>Moscow</wp:Title>
  </wp:Tile>
</wp:Notification>

Generating custom images

For this I thought of 2 approaches – one was to use the same technology that we’ve been talking about since .NET 1.1 days and use the Graphics class inside an HTTP Handler to generate images according to a set of parameters, or I could go out on a limb and utilize the power of WPF on the server-side to use XAML to layout our custom image and use Data Binding to wire up my custom data.  I chose the latter, because that’s how I roll Winking smile

I started with some code that Cori Drew pointed me at written by Laurent Bugnion (author of my most favorite MVVM Light framework) from his article Converting and customizing XAML to PNG with server-side WPF. His code sample included a library that makes short work of taking XAML from an external file and, through the setting of WPF Dependency Properties, render the XAML to a PNG based on the data values we pass in.

First, I added a web project to the sample’s solution and created a new HTTP Handler.  In here, we have to gather the information from the call to the handler to determine what we're supposed to do:

string xamlFileName = "Default";

var _parms = request.FilePath.Split(Char.Parse("/"));
var _filename = _parms[_parms.Length - 1];
var _parts = _filename.Split(Char.Parse("_"), Char.Parse("."));
var _city = _parts[0];
var _temperature = _parts[1];
var _conditions = _parts[2];

var _backgroundImage = String.Format(
    "http://{0}{1}/BackgroundImages/{2}.png",
    request.Url.Host,
    request.ApplicationPath,
    _conditions);

I tried using QueryString parameters to keep it a bit simpler, but that didn’t seem to work for me. I’m sure it was just some silly user error, but I decided to try and be a bit clever and munge the filename instead – something like http://myserver.com/ImageGenerator/10_London_Snow.tile.  Since we want to include a graphic indicating the type of weather we’re describing, I saved off all of Yochay’s images and reconstructed a URL to the static image using our good friend String.Format.

Once we know all the parameters, we need to load the XAML file from the server and call out to the replacement logic to update it’s dependency properties based on our supplied parameters.  Here’s a sample of the code I’m using to load the XAML and set these properties:

FileInfo xamlFile = new FileInfo(context.Server.MapPath(string.Format("~/XAML/{0}.xaml", xamlFileName)));

List<DependencyPropertyReplacement> replacements = null;

string[] customizeElements = new string[5]
{
    String.Format("BackgroundImage:{0}", _backgroundImage.Replace(":", "~")),
    String.Format("Temperature:{0}°", _temperature),
    String.Format("City:{0}", _city),
    String.Format("Conditions:{0}", FormatConditionsString(_conditions)),
    String.Format("LayoutRoot:Black")
};

PrepareCustomizableReplacements(customizeElements, ref replacements);

The method PrepareCustomizableReplacements and his friend MakeCustomizableReplacement use some really interesting code to attach to each of the supplied dependency properties and update them based on their type.  The code is not as clean as it could be, as we could have done some refactoring around the use of the switch statement, but for my purposes this is fine.

private void PrepareCustomizableReplacements(string[] elements,
    ref List<DependencyPropertyReplacement> replacements)
{
    if (replacements == null)
    {
        replacements = new List<DependencyPropertyReplacement>();
    }

    foreach (string nameValue in elements)
    {
        string[] nameValuePair = nameValue.Split(new char[] { ':' });

        // This cannot be handled in a generic way because the DP must be set with a value
        // of the correct type.
        switch (nameValuePair[0])
        {
            case "LayoutRoot":
                replacements.Add(MakeCustomizableReplacement(nameValuePair[0],
                    "Background", WpfUtility.MakeSolidColorBrush(nameValuePair[1], true)));
                break;
            case "BackgroundImage":
                var _image = WpfUtility.MakeBitmapImage(nameValuePair[1].Replace("~", ":"));
                replacements.Add(MakeCustomizableReplacement(nameValuePair[0], "Source", _image));
                break;
            case "Temperature":
            case "Conditions":
            case "City":
                replacements.Add(MakeCustomizableReplacement(nameValuePair[0], "Text", nameValuePair[1]));
                break;
        }
    }
}

private DependencyPropertyReplacement MakeCustomizableReplacement(string elementName, string propertyName, object value)
{
    DependencyPropertyReplacement replacement = new DependencyPropertyReplacement();
    replacement.ElementName = elementName;
    replacement.PropertyName = propertyName;
    replacement.Value = value;
    return replacement;
}

You can see from here that we're looping through each of the customization points that I specified in the last code sample, attaching to the specific dependency property on the XAML control, and updating their value.  There is some custom wizardry that’s going on behind the MakeBitmapImage method that I’ll talk about next.

Fun with images…

I ran into a snag trying to set the source on our Image control. As most of you probably know, we always preach that “anything you can do in XAML you can do in code”, which of course is true, but we don’t necessarily say how easy it’s going to be to create a code equivalent. Take the Image control for example.  It’s really easy for me to set the image up using something like this in XAML:

<Image Source=”MyImage.jpg” />

Now you know that we’re not actually setting the source of the Image object to a string value of “MyImage.jpg” right? We’re creating an Image object and loading it up from the image stored on disc specified in the path provided.  WPF has a really nice set of built-in ValueConverter objects that make things really easy for us to work with “magic strings”.  In my case, I had to do things a bit more manually:

public static object MakeBitmapImage(string filename)
{

    WebClient webClient = new WebClient();
    byte[] imageContent = webClient.DownloadData(filename);

    MemoryStream memoryStream = new MemoryStream(imageContent);

    BitmapImage imageSource = new BitmapImage();
    imageSource.CacheOption = BitmapCacheOption.None;
    imageSource.BeginInit();
    imageSource.StreamSource = memoryStream;
    imageSource.EndInit();

    if (imageSource.CanFreeze)
        imageSource.Freeze();

    return imageSource;
}

You'll first notice that we have to actually fetch the image from the web ourselves. Once we have the image, we need to load it into a BitmapImage object from which we can then assign to the Image.Source dependency property.  The last snag I ran into related to the Freezing of certain properties before you can assign them.  As it turns out, you need to “freeze” BitmapImage objects before you can assign them as a source for an ImageObject due to some interesting thread ownership issues.  I won’t go into detail here, but there are some nice references on StackOverflow and MSDN to help you understand the whys and wherefores.

Once I had the image created, Laurent’s code sample just writes it to the output stream and we’re golden.

    try
    {
        using (Stream stream = File.OpenRead(xamlFile.FullName))
        {
            using (MemoryStream memoryStream = new MemoryStream())
            {
                XamlToPngConverter converter = new XamlToPngConverter();
                converter.Convert(stream, 173, 173, memoryStream, replacements);

                // set the content type
                context.Response.ContentType = "image/png";
                memoryStream.WriteTo(context.Response.OutputStream);
            }
        }
    }
    catch (Exception ex)
    {
        throw new HttpException(404, "Image not found:" + xamlFileName, ex);
    }

At this point we have a working dynamic image generator. Cool, isn’t it?  Now all we have to do is wire it up to the Driver program so that the phone knows where to go grab the correct tile image.

Sending the right tile

Luckily, the rest of the changes were really minimal. Although there were a few tweaks to other parts of the driver program, the key change is in the definition of the URI:

private void sendTile()
{
    //TODO - Add TILE notifications sending logic here
    string weatherType = cmbWeather.SelectedValue as string;
    int temperature = (int)sld.Value;
    string location = cmbLocation.SelectedValue as string;
    List<Uri> subscribers = RegistrationService.GetSubscribers();
    var _uri = String.Format("http://localhost/ImageGenerator/{0}_{1}_{2}.tile", location, temperature, weatherType);
    ThreadPool.QueueUserWorkItem((unused) => notifier.SendTileNotification(
        subscribers, "PushNotificationsToken",
        _uri, temperature, weatherType.Replace("-", " "), OnMessageSent));
}

Once we had the proper URI for the image (one based on all the parameters we needed to decode) we only had one more important change to make – this time in the NotificationSenderUtility library.

In here, the expected behavior for sending a tile message is to send all three parts of the data – count, title and image.  In our case, we DON’T want the count coming across because it will just mess up our UX.  To accommodate, I just commented out the line that sets the Count value in the outgoing XML and we were good to go:

private static byte[] prepareTilePayload(string tokenId, string backgroundImageUri, int count, string title)
{
    MemoryStream stream = new MemoryStream();

    XmlWriterSettings settings = new XmlWriterSettings() { Indent = true, Encoding = Encoding.UTF8 };
    XmlWriter writer = XmlTextWriter.Create(stream, settings);
    writer.WriteStartDocument();
    writer.WriteStartElement("wp", "Notification", "WPNotification");
    writer.WriteStartElement("wp", "Tile", "WPNotification");
    writer.WriteStartElement("wp", "BackgroundImage", "WPNotification");
    writer.WriteValue(backgroundImageUri);
    writer.WriteEndElement();
    writer.WriteStartElement("wp", "Count", "WPNotification");
    //writer.WriteValue(count.ToString());
    writer.WriteEndElement();
    writer.WriteStartElement("wp", "Title", "WPNotification");
    writer.WriteValue(title);
    writer.WriteEndElement();
    writer.WriteEndDocument();
    writer.Close();

    byte[] payload = stream.ToArray();
    return payload;
}

With these changes in place, everything was wired up and worked exactly as I had hoped it would Smile

Now what?

It’s still not perfect – there is some code cleanup I’d like to do, and the images with text added to them don’t show up as crisp and clear as if we’d used the push infrastructure the way it was designed, but it’s a good start.  If you have any questions, post a comment and lets discuss it.  I’ve posted my code sample on Skydrive, so it should be easy to find:

Happy Push Notification-ing!

Development, Featured, MVVM, Silverlight, WP7

MVVM Light Messaging

This entry is part 7 of 8 in the series Windows Phone 7

Since I started using the MVVM Light toolkit, I’ve gotten lots of questions about the it. In this post, I’m going to show you the basics of using the Messaging infrastructure. In the sample application attached, we have the situation where a Master page with a list of data items is trying to move to the Details page to show the details for one specific item.  There are a couple of ways to do this, but the one I’ve starting using is the Messaging infrastructure in MVVM Light. It involves the ViewModels communicating with each other via a lightly-coupled messaging bus rather than a direct coupling or using the query string.  Let’s break it down…

The sample application displays a fixed set of data elements in a list on the main page.  When an item is selected from the list, it navigates to the details page and shows the details. Presuming you already have the main page working, here’s what’s left:

Step 1 – Send the message out to the bus

When you create a new ViewModel property using the MVVM Light snippets, the sample code that gets created asks you to make a decision between publishing the PropertyChanged event to the message bus or not.  In our case, we want to publish to the message bus.  This will allow registered receivers to pick up this message. So – inside the MainViewModel, we have this property:

public Person SelectedItem
{
    get
    {
        return _selectedItem;
    }

    set
    {
        if (_selectedItem == value)
        {
            return;
        }

        var oldValue = _selectedItem;
        _selectedItem = value;

        // Update bindings and broadcast change using GalaSoft.MvvmLight.Messenging
        RaisePropertyChanged(SelectedItemPropertyName, oldValue, value, true);
    }
}

The RaisePropertyChanged method includes two overrides – this one publishes to the Messaging infrastructure for us.  Now all we need is a listener…

Step 2 – Register the Details view model to listen for the appropriate message

Now that the message is getting published to the message bus, we need a receiver to pick it up and act on it.  In our case, that’s the DetailsViewModel. In the constructor for the ViewModel, we add the necessary code to register for receiving SelectedItem PropertyChanged messages like this:

public DetailsViewModel()
{
    Messenger.Default.Register<PropertyChangedMessage<Person>>(
        this,
        (action) => DispatcherHelper.CheckBeginInvokeOnUI( () => this.Item = action.NewValue )
    );
}

Notice the Register statement – we need to register for instances of the PropertyChangedMessage message that transport Person objects.  Our example is simple, so any type a PropertyChanged message is sent into the bus with a Person attached to it, the DetailsViewModel will pick it up.  If there is any disambiguation that needs to be made, there are a couple of other overrides to the Register method that allow you to provide a “token” (i.e. message name) as well as a switch to manage whether or not derived messages will also be picked up,

Since the GlobalViewModel locator creates and manages the lifetimes of our ViewModels, the DetailsViewModel is always instantiated and is available at the beginning of the application lifecycle to register for these messages.  When the messages arrive, even if we don’t navigate to the Details page, the DetailsViewModel is ready for us.

The full sample can be downloaded right here.

Development, WP7

WP7 Part 4: Morphing and Mapping

This entry is part 4 of 8 in the series Windows Phone 7

As stated in previous posts, this series represents my experimentation with the Windows Phone 7 developer tools.  It was suggested that I chronicle those adventures for everyone’s benefit, so here it is. There’s good and bad in that – the good part is that we have the opportunity to all learn together as my dabblings become a real, working application. The down side, is that as I learn new and better ways to do things, the project morphs to go along. That might be off-putting to some, but it’s how my brain works, so I hope you’ll continue to indulge me and follow along as we grow this application.

Migrating to a better MVVM Framework

One of the highlights of the version of the code that accompanies this post is the further migration towards a better MVVM implementation – specifically Laurent Bugnion’s very cool MVVM Light Toolkit. His framework makes it really easy to adopt MMVM in a very declarative way, and I’ve found using it to be quite fun too! So – that means that my home-grown MVVM implementation has now been replaced with MVVM Light. Here’s what I had to do to make that happen:

  • Download and install the bits from http://www.galasoft.ch/mvvm/getstarted/
  • Set references to the MVVM binaries
  • Create a ViewModel locator class (GlobalViewModel) to serve as a repository of all ViewModel classes
  • Register the new ViewModel locator in the App.xaml page:
<application.resources>
        <vm:globalviewmodellocator
                xmlns:vm="clr-namespace:CommunityMegaphone.ViewModels"
                x:key="Locator" />
<application.resources>
  • Create new ViewModel classes to replace the ones I had (minimal changes were needed to these classes to make them work in the new framework – I could almost just copy/paste all the interior code over).
  • Change the XAML documents to reference the ViewModel classes as the page’s DataContext. We do this by adding a new DataContext attribute to each of the Page classes. Here’s an example from the MainView.xaml:
DataContext="{Binding Source={StaticResource Locator},      Path=MainViewModel}"
  • Update the views to make sure they point to the proper location in the ViewModel classes to get the information they need

Please spend some time migrating your application to get a feel for all the steps involved. The MVVM Light Toolkit provides a set of helpers to make adoption go smoothly – one you’ll want to become familiar with is the DispatcherHelper. Make sure you initialize it during application startup, or it won’t function as you’d expect.

This helper makes it really easy to switch execution back to the UI thread to do UI updating. You simply call into the CheckBeginInvokeOnUI method, passing in a delegate for the code you want to run, and that code will be run on the UI thread. Here’s my sample Load method from the MainViewModel class:

public void Load()
{
    var catalog = CMEventsEntities.Instance;

    DateTime maxDate = DateTime.Now.AddMonths(3);
    DateTime minDate = DateTime.Now.AddMonths(-1);

    DataServiceQuery dsq = catalog.ApprovedEvents
                  "year(starttime) le " + maxDate.Year + " and " +
                  "month(starttime) le " + maxDate.Month + " and " +
                  "year(starttime) ge " + minDate.Year + " and " +
                  "month(starttime) ge " + minDate.Month)
         .AddQueryOption("$orderby", "starttime");

    dsq.BeginExecute( (a) =>
    {
        var results = dsq.EndExecute(a);
        DispatcherHelper.CheckBeginInvokeOnUI(() =>
        {
            Items.Clear();
            foreach (ApprovedEvents @event in results)
            {
                Items.Add(@event);
            }
        });
    }, null);
}

Make sure the application is up and running with the new configuration before moving on to the next step, which is to add Mapping capabilities to the details page.

Adding a Bing Map

At the end of episode 3, we left a space at the bottom of the details page for a map control. We want to update our application to display a map of the event location to make it easier for us to find the given event. This should be relatively easy as there are publicly available downloadable bits for Silverlighg 3 and Silverlight 4.

Unfortunately, the publicly available map controls for Silverlight 3 and Silverlight 4 have a dependency on System.Windows.Browser.dll, which is not currently supported by the WP7 framework. I was able to obtain a pre-release build of a WP7-friendly Bing Map control to develop and test against.

Unfortunately, I found out after I wrote this post that the WP7 Bing Maps control referenced in this post has not been made publically available, so I can not release the binaries.  I promise that I will update this post as soon as I am told that the binaries are made available to everyone.

The first step in adding the control is setting a reference to the 2 Bing Maps libraries – Maps and Maps.Common.

Next, we go into our DetailsPage.xaml and add a new XML namespace for the Map control library:

xmlns:map="clr-namespace:Microsoft.Phone.Controls.Maps;  assembly=Microsoft.Phone.Controls.Maps"

We can then add the Map control to our Grid control in the open slot at the bottom:

<map:Map Grid.Row="5" Grid.Column="0" Grid.ColumnSpan="2"  x:Name="MyMap" ZoomBarVisibility="Visible" ZoomLevel="15"  CredentialsProvider="...mykey..." Margin="5" />

There are number of options we can set. I’ve set the ZoomLevel to 15, so that we can get a close-in map (larger numbers = higher zoom level) set the display to Road and turned off animation so it will run faster on my 3G phone network.

To set up the map location and set the pin, we’re going to make some changes to the DetailsViewModel to raise an event when the loading is complete so that the DetailsPage can create the pushpin and place it on the map.

public void Load(int id)
{
    //TODO: Need to consider a way to cache the initial results and reuse here
    CMEventsEntities context = CMEventsEntities.Instance;
    var query = context.ApprovedEvents
        .AddQueryOption("$filter", "id eq " + id);
    query.BeginExecute((result) =>
    {
        var data = query.EndExecute(result);
        DispatcherHelper.CheckBeginInvokeOnUI(() =>
        {
            foreach (var item in data)
                Item = item;
            if (Item != null)
                LoadItemData();
            OnLoadComplete(new EventArgs());
        });
    }, null);
}

note to self: I need to find a good declarative way to set this up, but for now, the imperative method will work fine. I also need to come up a caching scheme for this data so I don’t have to go back to the database for the details page data. We’ll explore that in future versions of the application.

When this OnLoadComplete event fires, the associated View will respond by running some code to take the selected event from the ViewModel and plot a pushpin according to the associated longitude and latitude. Because the CM database returns the lat/long as one long string, I needed to write some code in the DetailsViewModel to split this out into two separate doubles – that code belongs in the VM and not in the View, so that is where I put it. Here’s the code from inside the event handler that shows how we create the pushpin and center the map on that location:

DetailsViewModel vm = this.DataContext as DetailsViewModel;
Pushpin pushpin = new Pushpin();
Location location = new Location()
{
    Latitude = vm.Latitude,
    Longitude = vm.Longitude
};
pushpin.Location = location;
MyMap.ZoomLevel = 15;
MyMap.Center = location;
MyMap.Children.Add(pushpin);

Now time to test – when we click on an item to bring up the Details page, it should load the map once the data is fetched from the database. The pushpin looks a bit wonky, but I’m not sure what’s going on there. I think there might be a resource issue in the bits I’m running, so I’ll see what I can find out about making that look nicer.

That is it for this post – next time we’re going to look at adding an application bar to control some settings for our application, and investigate integrating with the location sensor to find events near our position.

Development, Windows, WP7

WP7 Part 3: Navigation

This entry is part 3 of 8 in the series Windows Phone 7

NOTE: Since the first article was released, the WP7 tools have been updated with an April Refresh. The original post has been updated to reflect the proper download to get the April CTP-friendly code and we will use that as a starting point for this post.

OK – I have a confession to make. Actually, it’s more of something I have to admit – I made a mistake. In picking NerdDinner as the foundation for this blog series, I figured that having all kinds of screwball data in it would be perfectly OK since it wasn’t a “real” application, and I didn’t want to worry about working with actual live sites. That turned out to be a mistake. Although the NerdDinner site is a great idea, and a great learning tool for ASP.NET MVC developers, the data is *really* bad, and not something I want to continue working with for this series. SO… I’ve re-written the application from NerdDinner to use Community Megaphone, an event management and listing site maintained by my friend and collegue G. Andrew Duthie (a.k.a. DevHammer). I’ve also simplified things a bit and removed the repository pattern (at least for now) in favor of a more traditional approach, that we can look later at refactoring when we introduce an IoC container and begin to do DI, etc. So, for now, let’s just pretend that we’ve been working with CM all along, shall we?

Out of the box, the Windows Phone 7 tools give you a pretty good starting place for your application. The List template is based on the MVVM pattern, includes some sample code to help you better visualize your solution, and two pages to get you started: main page (list of items) and details page (details for an item). In this post we�ll explore the page navigation options available to the WP7 developer, starting with the OOB experience.

The sample application uses an, um� interesting approach to navigating from one page to another. The idea is simple: choose an item from the main list, show a cool page transition animation, then navigate to the new page with the details showing up. The way they accomplish this is to trap the left mouse button up event, store off the currently selected item, and start a page transition (i.e. storyboard). When the animation is complete, the main page uses the built-in Navigation framework to navigate the application to the new page. For that details page to get its data context, the main page (remember that he�s still in control until the current method exits) grabs hold of the root visual in the details page and sets that�s page�s DataContext attribute to the saved off currently selected item in the list.

hmmm.

I don�t know about you, but this somehow just plain bothers me. I realize that there are always several ways to skin a cat, but this one seems particularly icky to me. I don�t think it�s the job of the main page to force a data context on a details page. The details page should be told which object to use as its reference, or a key to that object perhaps, and then allowed to render itself.

To accomplish this in WP7 there are a couple of options:

  1. Continue to attach to the details page after navigating to it and send it the data on which it should operate � just do it in a slightly less icky way
  2. Send a parameter to the details page so that when it opens, it knows which object to get from the database, then it makes that stuff happen.
  3. Store the selected item into Isolated Storage (or some other caching mechanism), navigate to the new page, and then retrieve it again.

Navigation in WP7 is based on a similar framework to what you�re used to with ASP.NET. It uses a simple URI-based scheme for indicating which page in your application to load and navigate to.

Uri theUri = new Uri(�/DetailsPage.xaml�, UriKind.Relative);
NavigationContext.Navigate(theUri);

In this example, the NavigationContext loads the DetailsPage.xaml and navigates the application there using an unadorned, relative URI. Note: absolute URIs are not supported – you can’t use this mechanism to cause the built-in web browser to open a web page. There is a different technique for that which we’ll look at later. One thing you get for free with the Navigation framework is the ability to respond smartly to the Back button on the phone. After navigating to a new page, if the user presses the Back button on the phone, the application will go back to the last item in the Navigation stack. Pretty smart, eh?

OK – enough bakground, let’s go build something. In the MVVM world, the ViewModel takes the responsibility for loading itself on behalf of it’s View. In our case, we�re going to need a ViewModel that will do this for a given Event based on it’s associated Event ID. We�ll start by changing the call to the Details page to accept an Event ID as a parameter in the Navigation Context

private void PageTransitionList_Completed(object sender, EventArgs e)
{
    // Set datacontext of details page to selected listbox item
    //NavigationService.Navigate(new Uri("/DetailsPage.xaml", UriKind.Relative));
    //FrameworkElement root = Application.Current.RootVisual as FrameworkElement;
    //root.DataContext = _selectedItem;

    Uri theUri = new Uri("/DetailsPage.xaml?eventId=" + _selectedItem.id, UriKind.Relative);
    NavigationService.Navigate(theUri);

}

The QueryString, you say? Yes, the QueryString. Once inside the Details page, we can then use the NavigationContext again to retrieve the associated eventId and load the ViewModel with the right data:

void DetailsPage_Loaded(object sender, RoutedEventArgs e)
{
    int eventId = 0;

    //TODO: put some better error handling in here
    Int32.TryParse(NavigationContext.QueryString["eventId"], out eventId);

    // Set the data context of the listbox control to the sample data
    vm.View = this;
    DataContext = vm;
    vm.LoadFromId(eventId);
}

The view model can then use our same tricks from before to load the specific Event:

public void LoadFromId(int eventId)
{
    var catalog = CMEventsEntities.Instance;

    //var query = from e in catalog.ApprovedEvents
    //            where e.id == eventId
    //            select e;
    //DataServiceQuery dsq = query as DataServiceQuery;

    DataServiceQuery dsq = catalog.ApprovedEvents
        .AddQueryOption("$filter", "id eq " + eventId);

    dsq.BeginExecute(new AsyncCallback(a =>
    {
        var result = dsq.EndExecute(a).FirstOrDefault();

        View.Dispatcher.BeginInvoke(() =>
        {
            Item = result;
            NotifyPropertyChanged("Item");
            NotifyPropertyChanged("PageTitle");
        });

    }), null);
}

Note that this time, I was unable to get the typical LINQ query to retrieve the data I wanted, so I reverted to the AddQueryOption method of the DataServiceQuery to get what I needed from the OData service. I think this might be due to a bug in the pre-release version of the OData provider I’m using, becuase I can’t see any reason why the straight-up LINQ syntax shouldn’t work. Anyway, the pattern is the same as before: create a DataServiceQuery based on the data you want to retrieve, call BeginExecute, when the results come back they get processed on the UI thread in order to update the UI (note to self: I should probably create a code snippet for this so I don’t have to keep typing it all the time…) I’m also directly raising the NotifyPropertyChanged event for both the Item (our target Event) and the PageTitle property (which is based on the selected Item). That way, our UI will stay in sync with the data we’re maintaining in the ViewModel.

After this, and a little bit of Data Binding magic, our UI is populated and we have our details page!

One thing left to do related to Navigation – that pesky URL. As I mentioned before, you can’t use the built-in Navigation Framework to open a Web Browser to a given URL. You can try it if you want to – I’ll wait here… Didn’t work did it? Here’s what you can do:

  • Web Browser Control: Create a separate page that hosts a web browser control, and navigate there using the target URL as a QueryString property. When the web browser page loads, you can navigate the web browser control bring up the page you want. This is an OK option, but depends on what you’re really trying to accomplish/
  • WebBrowserTask: Using the WP7 Task infrastructure (I know, we haven’t covered that yet), you can launch the phone’s default web browser on a given URL. This is the method I’ll choose for this application, and I’ll show the code that makes it work.

We’ll be covering the Tasks infrastructure in more detail as part of a later post, but for now, just go with me…

There are many Task objects in the Windows.Phone.Tasks namespace – they are all designed to do a specific type of thing: launch some process to either display information, or capture information. The one we care about here, is the WebBrowserTask object. It’s whole purpose in life is to launch the phone’s built-in web browser to a specific URL. That being said, it couldn’t be easier to use. For our application, we’re displaying the event URL in a HyperlinkButton and capturing the Click event:


Once this event fires, we create an instance of the WebBrowserTask object, set it’s URL and call the Show() method to get the job done.

private void HyperlinkButton_Click(object sender, RoutedEventArgs e)
{
    WebBrowserTask task = new WebBrowserTask();
    task.URL = vm.Item.eventUrl;
    task.Show();
}

Clicking on the link launches the web browser and we can see the event in all of its default glory. Pressing the Back button takes us back to the details page, and back again will take us back to the home page.

That’s it for this post. In future posts, I’m planning to add an application bar that will allow us to modify our query parameters controlling what events we show in the main list, and hopefully integrate the Bing Map engine to show more information about the selected event.

Development, WP7

WP7 Part 2 – Working with Data

This entry is part 2 of 8 in the series Windows Phone 7

This is the second in my series of WP7 articles where I work towards building my first full-featured WP7 application. Part 1 was a �getting started� type of post, where I discussed installation of the tools and stuff you need to get started. This time we tackle the building out of our application by addressing our data needs.

The Application

image For my first WP7 app, I have chosen to build a NerdDinner mobile client � NerdDinner ToGo. The application will allow us to find events that we�re interested in attending, and submit an RSVP for those we want to attend. We�ll also look into adding some social networking integration, perhaps with Twitter, or FourSquare, or similar. Eventually, the final application will use almost, if not all of the most compelling WP7 features such as notification, accelerometer & location sensors as well as all the �normal� stuff you�d expect to find in an application like this. The only challenge I�ve found with using this application as the foundation for this series of posts is that the data in NerdDinner is completely bogus. This is not too bad, but it will create a pretty crazy experience for our end users as they have to navigate through the data other folks have entered in. Maybe we�ll figure out a way to deal with this in future posts, but for now, let�s push on to retrieving data.

Lets start this project off with a new project based on the WP7 List Application template. This template provides more than the plain-�ole WP7 application template � it gives us a foundation for list+details types of applications that we can modify without having to create everything from scratch. The main page will serve up our list of upcoming dinners, and the details page will show us detailed information about a particular dinner. We�ll implement the details page in the next post. For now, let�s focus on getting a list of dinners for our app to start off with.

Retrieving Data from NerdDinner

There are lots of places on the net to get data, and that data comes in lots of different forms. For this application, NerdDinner offers an OData data feed, which is PERFECT for our needs. Although OData is not the only way to get data into a WP7 application, it certainly is a convenient way

For those not familiar with OData, please check out the references at the bottom of this post for more details. There are many great references as well as videos that do a great job of explaining what OData is, and why it�s important.

The OData feed for NerdDinner.com offers two services � one to manage the actual Dinners, and one to manage the RSVPs. Normally, with a WPF or Silverlight application, we could easily add a service reference to this OData endpoint using the �Add Service Reference� feature of Visual Studio. Unfortunately, this feature is currently broken in the CTP tooling, so we have to use some alternate methods. One approach could be to open another instance Visual Studio 2010 and create a new Console application, run the tooling from there, and copy the code into our WP7 project. Another approach is to use the command line tooling supplied with the .NET Framework SDK and use the output in our project. The latter option is the one we�ll go with here.

The command you�ll need is datasvcutil.exe, as found in the .NET Frameworrk SDK. The parameters you need to supply include the endpoint of the service reference, the name of the output file, and a pair of parameters that enable data binding to the results. Once the class is generated, we can simply add it to our project and we�re good to go.

Here�s the command I am using, as run from the Visual Studio 2010 Command Prompt:

datasvcutil /uri:"http://nerddinner.com/Services/OData.svc"
            /dataservicecollection /version:2.0
            /out:nerddinner.cs

The classes that get generated include NerdDinnerEntities, which serves as our primary context for querying and updating entities within the NerdDinner system, and a set of individual data classes that represent entities in the NerdData system. NerdDinnerEntities, as a type of DataServiceContext, allows me to use familiar LINQ queries to retrieve data from NerdDinner � we�ll get to that in a few minutes. For now, let�s create a new folder in our project called �Models� and add this new file to it. You should also change the namespace to fit the [ProjectName].Models namespace to keep things clean. We also need to add a Project Reference to the OData Client OData Client Library for WP7. This library is currently a separate download (see links below), but will eventually be included (and wired up) via the Add Service Reference tooling in the WP7 tools for VS2010.

Once we have this file created, we need to create a Catalog or Repository infrastructure wrapper around it. This wrapper will allow us to decouple the underlying data store from the application, giving us the flexibility to use dependency injection and mocking as our needs dictate. For now, we’re going to start with the most basic infrastructure (an interface that describes the catalog and a single concrete implementation) but will look at expanding this for the future. Our v1 interface is extremely simple:

public interface IDinnerCatalog
{
    void GetDinners();
    event EventHandler&lt;DinnerLoadingEventArgs&gt; 
              DinnerLoadingComplete;
}

The interface currently defines only the GetDinners method (which will return all the dinners supplied by the data source) and an Event Handler for indicating that the data loading is complete. In the future, we’ll expand this to support filter, updating, RSVPs and more. The concrete implementation for this interface is a bit more involved:

public class NerdDinnerCatalog : IDinnerCatalog
{
    public event EventHandler&lt;DinnerLoadingEventArgs&gt; 
	DinnerLoadingComplete;
 
    private Uri theServiceRoot;
    private NerdDinnerEntities theEntities;
 
    public NerdDinnerCatalog()
        : this(new Uri(&quot;http://nerddinner.com/Services/OData.svc&quot;, 
		   UriKind.Absolute))
    {
    }
 
    public NerdDinnerCatalog(Uri serviceRoot)
    {
        theServiceRoot = serviceRoot;
        theEntities = new NerdDinnerEntities(theServiceRoot);
    }
 
    public void GetDinners()
    {
        var query = from d in theEntities.Dinners
                    orderby d.EventDate descending
                    select d;
        ExecuteQuery(query as DataServiceQuery&lt;Dinner&gt;);
    }
 
    // Call the query asynchronously and update the collection
    void ExecuteQuery(DataServiceQuery&lt;Dinner&gt; qry)
    {
        // Execute the query
        qry.BeginExecute(new AsyncCallback(a =&gt;
        {
            IEnumerable&lt;Dinner&gt; results = qry.EndExecute(a);
 
            if (DinnerLoadingComplete != null)
            {
               DinnerLoadingComplete(this, 
                 new DinnerLoadingEventArgs(results));
            }
        }), null);
    }
}
 
public class DinnerLoadingEventArgs : EventArgs
{
    public IEnumerable&lt;Dinner&gt; Results { get; private set; }
 
    public DinnerLoadingEventArgs(IEnumerable&lt;Dinner&gt; results)
    {
        Results = results;
    }
}

The catalog is created based on a URI that points to our data source, and raises an event when the data loading is complete. The collection of retrieved Dinner objects is returned to the caller via the DinnerLoadingEventArgs. Using events helps decouple the retrieving of data from the main processing thread and allows us to free up the UI while data loading is in progress.

Create the Dinners ViewModel

Now that we have the catalog to help us get our data out of the database, we need to create a ViewModel. The ViewModel is responsible for interactions between the Model and the View. In our case, the DinnersViewModel will utilize the Catalog to fetch Dinner records from the OData data source store them in an instance property, implemented as an ObservableCollection for the view to databind to. As per the MVVM pattern, all interaction with the catalog is managed by the ViewModel – not by the View. In this first phase, we�re going to just do a simple search to return all the dinners, but we’ll expand on this in the future.

public DinnersViewModel(IDinnerCatalog catalog)
{
    theCatalog = catalog;
    theCatalog.DinnerLoadingComplete +=
        new EventHandler&lt;DinnerLoadingEventArgs&gt;(
              Dinners_DinnerLoadingComplete);
}

public void LoadDinners()
{
    theCatalog.GetDinners();
}

void Dinners_DinnerLoadingComplete(
    object sender, DinnerLoadingEventArgs e)
{
    // Fire Event on UI Thread
    View.Dispatcher.BeginInvoke(() =&gt;
        {
            // Clear the list
            theDinners.Clear();

            // Add the new Dinners
            foreach (Dinner d in e.Results) 
                theDinners.Add(d);

            if (LoadComplete != null) 
                LoadComplete(this, null);
        });
}

The LoadDinners method passes on the request for data to the catalog to fetch the appropriate Dinner records. Because the catalog raises an event when the data loading is complete, the ViewModel will register for that event and, once raised, will pull the data into the local collection. That collection, here in the ViewModel, is used by the View for databinding purposes.  This way the , so once it changes, the UI automatically updates. An important note here: you might notice that the DinnerLoadingComplete event handler uses the Dispatch object to update the local Dinner collection on the main UI thread. Don’t forget to do this in your code or you’ll get a runtime error.

Update the UI

Now that our data is coming back from the OData data feed via the catalog, and is populating the ViewModel, it’s time to wrap up by creating the View. In our case, since we used the List Application template, we can utilize most of the code in the MainPage.xaml and just modify it for our needs. First we need to add some code to wire up the ViewModel to the page:

xmlns:vm="clr-namespace:NerdDinnerToGo.ViewModels"

...

<phoneNavigation:PhoneApplicationPage.Resources>
    <vm:DinnersViewModel x:Key="MyViewModel" />
    ...

Notice that we’re declaring access to our ViewModel declaratively instead of in the code. This probably a different approach for you than you’ve done in the past. Using this declarative approach allows us a much richer data binding experience and less code to write and maintain.

Now we need to update the ListBox to wire up to the data dource and to show the data elements that we need from our Dinner objects:

<ListBox x:Name="ListBoxOne" 
         ItemsSource="{Binding Path=Dinners, 
                               Source={StaticResource MyViewModel}}" 
         MouseLeftButtonUp="ListBoxOne_MouseLeftButtonUp" 
         Style="{StaticResource PhoneListBox}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <mpc:ListViewItem 
                 Layout="TextAndDetailsWithIcon" 
                 Text="{Binding Title}" 
                 Details="{Binding EventDate}" 
                 Style="{StaticResource PhoneListBoxItemLayout}"/>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

Now that the ViewModel is declared, lets wire it up.

public MainPage()
{
    InitializeComponent();

    SupportedOrientations = SupportedPageOrientation.Portrait;
    Loaded += new RoutedEventHandler(MainPage_Loaded);

    PageTransitionList.Completed += 
         new EventHandler(PageTransitionList_Completed);

    viewModel = this.Resources[&quot;MyViewModel&quot;] 
         as DinnersViewModel;
    viewModel.View = this;
    viewModel.LoadDinners();
}

So there isn’t a lot of code here, but it’s the remaining glue to get things up and running. When the LoadDinners method finishes, the UI will become responsive and the ViewModel will automatically update its Dinner collection with the search results.

image

Summary

In this article I have shown you how to create a basic WP7 application and retrieve data for it. To accomplish that, we implemented the MVVM pattern with a Data Catalog Repository to retrieve our data, maintain it in the ViewModel, and used Silverlight databinding to wire it up to the UI.  In the next post, I�ll show how you can use the page navigation infrastructure to implement a details page that shows additional information about the selected Dinner.

References

Development, Uncategorized, WP7

Developing for Windows Phone 7

This entry is part 1 of 8 in the series Windows Phone 7

This is my first in a series of posts all about developing applications for Windows Phone 7 using Silverlight. After what I saw at the WPC and experienced at MIX10, I knew that I wanted to get involved in this as quickly, and as deeply as possible. I’m going to share with you my learning as I go through them, so that hopefully you can grow in experience along with me as you wait patiently for this Christmas when the WP7 devices will become available. My goal is to become an expert WP7 developer right in front of your very eyes!

Windows Phone

For those that don’t know, Microsoft announced recently the new Windows Phone platform – Windows Phone 7 Series (recently renamed to Windows Phone 7 and abbreviated by me in this blog as WP7). The development platform is split – as an option, or combined – to be Silverlight and XNA. Silverlight is a great general-purpose option for folks doing personal productivity applications, fun casual games, or just about anything. What’s great about them choosing Silverlight as a dev platform is that many people are already experienced with Silverlight or WPF, and making the transition to WP7 is a total snap. XNA is great for building high-quality 3D interactive games that will really knock people’s socks off on Windows, XBOX and now Windows Phone 7 Series.

In this kickoff post, I’m going to describe the process for getting your dev environment set up, and some additional learning resources for you to use as you follow along with me as we learn to build WP7 applications. In future posts we’ll tackle data access, MVVM, the application model, notification and sensor platforms, hub integration, security and more, so tune into my WP7 category feed for updates to this series and other interesting WP7 tidbits. For now, let’s get started by putting our environment together and making sure it works.

WP7 Learning Resources

Besides this blog, there are a number of great resources out there for learning about WP7. I’ve been assembling a list of those links on my delicious account at http://delicious.com/chriskoenig/wp7. As I find new and interesting things, I’ll keep that list updated, so you can check back there frequently, or subscribe to the feed directly at http://feeds.delicious.com/v2/rss/chriskoenig/wp7. I want to call out a couple as top-priorities on your list of places to get started:

  1. http://developer.windowsphone.com this is the central hub of information for WP7. You can download the tools here as well as get updates on information coming from the WP7 team
  2. Windows Phone Developer Blog – the official blog of the WP7 team
  3. @wp7dev – the official WP7 Twitter account
  4. WP7 Forums – these are the WP7 forums. Lots of great conversations going on there!

Beyond that, knowledge of Silverlight will be assumed. If you are not already an established Silverlight developer, you might want to take some time between this intro post and the next one to brush up on a couple of key Silverlight concepts including layout, data binding, styling and networking. There are plenty of tutorials out on http://silverlight.net for you to enjoy.

Setting up your Environment

Installing the software is really easy – the WP7 team has done a great job packaging things up into a single installer to make things simple. Here’s the link for the installer:

http://www.microsoft.com/downloads/details.aspx?FamilyID=2338b5d1-79d8-46af-b828-380b0f854203&displaylang=en

This one-stop-shop will install everything you need to get started with WP7 development. A couple of notes:

  • Installation of the tools does NOT require any previous version of VS2010, although it will integrate nicely with the RC if you already have that installed
  • The currently build of the WP7 dev tools (as of this writing) will not work with Visual Studio 2010 RTM. Stay with the RC until the tools are updated if you want to do WP7 development (for now).
  • You can not run the dev tools (specifically the Emulator) in a VM because of WP7 Emulator is actually a VM (more on that later). To do WP7 development, you’ll need to run the tools “on the metal”. You can run them in a Boot-to-VHD hosted partition, so that is an option for you as well.

Testing it Out

image

Once you have the tools installed, fire them up. You’ll notice the “Visual Studio 2010 Express for Windows Phone” icon in your start menu, so let ‘er rip. There are three project types – Windows Phone Application, Windows Phone List Application, and Windows Phone Class Library. The first is a clean, blank slate that works like most VS “File->New” project templates. Notice that the design surface is nice and big, and represents the entire device. When you press F5 to launch the debugger, you can see the Emulator kick in and display your application:

As I mentioned earlier, the emulator is actually more of a Virtual Machine than an emulator. Instead of pretending to be the WP7 OS, it runs the actual WP7 OS inside a VM. imageToday’s Emulator doesn’t support all of the WP7 OS features (location and accelerometer support is missing), but it does a good start at representing many of them including location, and orientation – we’ll dive into all of these features in future posts. For now, it looks like the emulator is up and running, and the application deployed as expected. If your emulator doesn’t start up correctly – don’t be alarmed. I have run into a few instances where various problems occur. Restarting the debugging session, or restarting the Emulator always fixes this problem, but I try really hard not to ever restart the Emulator if I don’t have to. It’s not so important now, but it will make a bigger difference once we get into more advanced topics like the Notification subsystem.

I realize that this was an incredibly rudimentary post, but in the interest of completeness, you have to start somewhere, and I almost always like to start at the beginning. Don’t be disheartened, those of you with higher expectations. In the next post, we’ll dive into retrieving and manipulating data, and exploring the navigation system. We’ll also talk about how the MVVM pattern can be applied to our application. Beyond that, we’ll start working with the notification and persistence bits, integrating with the various hubs and other OS level hooks, and more. Stay tuned; until next time!