The blog of dlaa.me

Posts tagged "Windows Phone"

Happy Birthday, FeedWorm! [A simple, efficient (free!) Google Reader client for keeping up with RSS feeds on Windows Phone]

FeedWorm feed view

A little over a year ago, I got tired of searching for a Google Reader client on Windows Phone that worked exactly how I wanted. So I started writing one myself. My plan was to create a simple, efficient app that began by doing as little as possible - and gradually add more advanced features as time allowed. My goal was to understand the complete end-to-end experience of writing and publishing an application in the phone ecosystem.

I released the first version of FeedWorm one year ago today. It was free then; it remains free now. And while FeedWorm has a few more features today than when it started, it's still very much an exercise in minimalism (which helps keep it fast!).

To be clear, there are plenty of good Google Reader clients in the Marketplace and if one of them already meets your needs, there's little reason to switch. But if you're looking for something different - and aren't very demanding - FeedWorm might right for you. :)

 

[Click here to learn more about FeedWorm]

 

"If I have seen further, it is by standing on the shoulders of giants" [An alternate implementation of HTTP gzip decompression for Windows Phone]

The HTTP protocol supports data compression of network traffic via the Content-Encoding header. Compressing network traffic is beneficial because it reduces the amount of data that needs to be transmitted over the network - and sending fewer bytes obviously takes less time! The tradeoff is that it takes a bit of extra work to decompress the data, but because the bottleneck is nearly always network, HTTP compression should be a win pretty much every time. And when you're dealing with comparatively slow, unreliable networks like the ones used by cell phones, the advantages of compression are even more significant.

Aside: Because most networks are lossy and transfer data in packets, sending just one fewer byte can be meaningful if it reduces the number of packets.

 

You might reasonably expect that enabling compression for Windows Phone web requests is as simple as setting the HttpWebRequest.AutomaticDecompression property available since .NET 2.0. Unfortunately, this property is not supported by current versions of the Windows Phone platform, so it's up to application developers to add HTTP compression support themselves. Consequently, a number of home-grown solutions have cropped up.

One popular example is Morten Nielsen's GZipWebClient. Naturally, Morten didn't want to implement his own compression library, so he's using SharpZipLib to do the heavy lifting. This is a great example of reuse, but it's important to note that SharpZipLib is licensed under the GNU General Public License (GPL) and some developers won't be comfortable with the implications of using GPL code in their own project. (For more on what those implications are, the Wikipedia article for GPL has a fairly detailed overview which includes mention of ambiguities around the definition of "derivative works".)

Aside: Of course, there are other options. Another popular library is DotNetZip which claims to be under the MS-PL (Microsoft Public License), the same permissive "do pretty much whatever you want with the code" license I use for this blog. However, a brief look at the license files it comes with suggests maybe that's not the whole story because there are at least four other licenses called out there.

As you can probably tell, I'm not the biggest fan of lawyers, ambiguity, or unnecessary risk [ :) ], so I'm always happy to have a simple, "no restrictions" solution - even if that means I have to create one myself. In this case, what I wanted was a way to decompress gzip data on Windows Phone without needing a separate library. That's when I remembered another of Morten's posts, this one about unzipping files under Silverlight. I figured that maybe if I put the chocolate in the peanut butter, I could come up with a simple, dependency-free solution to the gzip problem on Windows Phone!

 

The basic idea is to create a bit of code that customizes the user's WebClient/HttpWebRequest to add the Accept-Encoding header. Once that's in place, servers that support gzip automatically compress their response bodies. To decompress the downloaded response on the phone, another bit of code is used to wrap the compressed response stream in a ZIP archive and hand it off to Application.GetResourceStream which does the heavy lifting and provides access to the decompressed response stream. What's nice about this technique is that the decompression implementation is part of the Silverlight framework - meaning applications don't need to pull in a bunch of external code or increase their size!

I wanted this to be easy, so I've created a WebClient subclass and all you have to do is change this:

client = new WebClient();

Into this:

client = new GzipWebClient();

After which your application's HTTP requests will automatically benefit from gzip compression!

Of course, some people like to work a little closer to the metal and I've done a similar thing for the HttpWebRequest/HttpWebResponse crowd. Change this:

request = WebRequest.CreateHttp(_uri);
request.BeginGetResponse(callback, request);
// ... response = (HttpWebResponse)request.EndGetResponse(result);
stream = response.GetResponseStream();
// ...

Into this:

request = WebRequest.CreateHttp(_uri);
request.BeginGetCompressedResponse(callback, request);
// ... response = (HttpWebResponse)request.EndGetResponse(result);
stream = response.GetCompressedResponseStream();
// ...

And you're set!

 

Great, that's all well and good, but does any of this really matter? Less is clearly more, but is there actually a noticeable difference when using gzip? I wanted to answer that question for myself, so the sample application for this post not only exercises the code I've written, it also acts as a simple, real-time performance report! The sample makes continuous requests for http://microsoft.com/ using WebClient, standard HttpWebRequest/HttpWebResponse, my custom GzipWebClient, my Compressed helpers for HttpWebRequest/HttpWebResponse, and (optionally) Morten's GZipWebClient (for comparison purposes). As the data is collected, it's charted via the Silverlight Toolkit's Data Visualization library (which I've previously shown running on Windows Phone).

Here's what it looks like running in the emulator using a wired connection:

GzipDemo on Windows Phone

In the chart above, you can clearly see which requests are using gzip and which aren't! Not only are the gzip-enabled requests noticeably faster on average, they're nearly always faster even in the worst case. What's more, while there's variability for both kinds of requests (that's part of how the internet works), the delta between best/worst times of gzip-compressed requests is smaller (i.e., they're more consistent).

That's pretty compelling data, but the real benefit comes when the phone's data connection is used. Here's the output from the same app using the cell network (via Excel this time):

HTTP Request Performance

All our previous observations remain true - and are even more pronounced in this scenario. Gzip-compressed HTTP requests are significantly faster (taking less than half the time) and more predictable than traditional requests for the same data.

Awesome!

Aside: Based on the chart above, it seems reasonable to claim all three gzip solutions are equivalent. That said, if you squint just right, it looks like using HttpWebRequest is - on average - marginally quicker than using WebClient (as you'd expect; WebClient calls HttpWebRequest under the covers). Additionally, SharpGIS.GZipWebClient appears to be - on average - very slightly quicker than Delay.GzipWebClient (which is also not surprising when you consider the hoops my code jumps through to avoid the external dependency). Bear in mind, though, that these differences only really show up at the millisecond level, and seem unlikely to be significant for most real-world scenarios.

 

[Click here to download the source code for the gzip helper classes and the sample application shown above]

OR

[Click here to visit the NuGet gallery page for Delay.GzipWebClient which contains the code for both gzip helper classes]

 

Notes:

  • Using the code I've authored is quite easy:

    • If you want to use GzipWebClient, simply add the GzipWebClient.cs and GzipExtensions.cs files to your project, reference the Delay namespace, and replace any instances of WebClient.

    • If you're a HttpWebRequest/HttpWebResponse fan, you only need to add GzipExtensions.cs to your project, reference the Delay namespace, and invoke the extension methods HttpWebRequest.BeginGetCompressedResponse and HttpWebResponse.GetCompressedResponseStream (as shown above).

  • By default, the sample application does not include Morten's GZipWebClient because I don't want to get into the business of distributing someone else's code. However it's easy to include - the following comment in MainPage.xaml.cs tells you how:

    // For an additional scenario, un-comment the following line and install the "SharpGIS.GZipWebClient" NuGet package
    //#define SHARPGIS

    The code to use that assembly is already in the sample application; you just need to provide the bits if you want to try it out. :)

  • The implementation of the gzip-to-ZIP wrapper is fairly straightforward: it reads the gzip-compressed response from the server, wraps it in a stream that represents a valid ZIP archive with a single file compressed using the deflate algorithm which both specifications share, and hands that off to the Silverlight framework to return a decompressed stream for that file. To be clear, the compressed data isn't altered - it's simply re-packaged into a format that's more useful. :) If you're interested in the specifics, you'll probably want to familiarize yourself with the gzip specification and the ZIP file specification and then have a look at the code.

  • There are two minor inefficiencies in my code, one of which seems unavoidable and the other of which could be dealt with.

    • The unavoidable one - and the reason I think SharpZipLib might be a smidge quicker - is that the size/checksum data for the gzip data is provided at the end of the download stream, but is needed at the beginning of the wrapper stream. If the correct values aren't used, the ZIP wrapper will be rejected - but those values are not known until the entire response has been downloaded. Therefore, it's not possible for my implementation to proactively process the data while it is being downloaded; the download must be buffered instead. A decompression library won't suffer from this limitation and ought to be quicker as a result.

    • The avoidable inefficiency is that a single copy of the input data is made when creating the ZIP wrapper stream. To be clear, this is the only time data is copied (I've structured the code so there isn't any buffer resizing, etc.), but it's not technically necessary because the ZIP wrapper stream could operate directly from the download buffers. I may make this improvement in the future, but expect the performance difference to be negligible.

 

Compressing HTTP traffic is a pretty clear win for desktop applications - and an even bigger benefit for mobile apps communicating over slower, less reliable cellular networks. The Windows Phone platform doesn't make using gzip easy, but it's possible if you're sufficiently motivated. For people who aren't intimidated by licenses, there are already some good options for gzip - but for those who aren't comfortable with what's out there, I'm offering a new option under one of the most permissive licenses around.

I hope you find it useful!

Know your place in life [Free PlaceImage control makes it easy to add placeholder images to any WPF, Silverlight, or Windows Phone application!]

One of the challenges with referencing online content is that you never know just how long it will take to download... On a good day, images show up immediately and your application has exactly the experience you want. On a bad day, images take a looong time to load - or never load at all! - and your application's interface is full of blank spaces. Applications that make use of remote images need to be prepared for variability like this and should have "placeholder" content to display when the desired image isn't available.

Of course, there are a variety of ways to deal with this; I thought it would be neat to create a reusable, self-contained class and share it here. I envisioned a simple control that "looked" like a standard Image element (i.e., had the same API), but that seamlessly handled the work of displaying placeholder content before an image loaded and getting rid of it afterward. Naturally, I also wanted code that would run on WPF, Silverlight, and Windows Phone! :)

 

<delay:PlaceImage
 PlaceholderSource="PlaceholderPhoto.png"
 Source="{Binding ImageUri}"/>

The result of this exercise is something I've called PlaceImage. PlaceImage has the same API as the framework's Image and can be dropped in pretty much anywhere an Image is used. To enable the "placeholder" effect, simply set the PlaceholderSource property to a suitable image. (Aside: While you could specify another remote image for the placeholder, the most sensible thing to do is to reference an image that's bundled with the application (e.g., as content or a resource).) PlaceImage immediately shows your placeholder image and waits for the desired image to load - at which point, PlaceImage swaps it in and gets rid of the placeholder!

 

I've written a sample application for each of the supported platforms that displays contact cards of imaginary employees. When the sample first runs, none of the remote images have loaded, so each card shows the "?" placeholder image:

PlaceImageDemo on Windows Phone

After a while, some of the remote images will have loaded:

PlaceImageDemo on Silverlight

Eventually, all the remote images load:

PlaceImageDemo on WPF

Thanks to placekitten for the handy placeholder images!

 

Making use of online content in an application is easy to do and a great way to enrich an application. However, the unpredictable nature of the network means content might not always be available when it's needed. PlaceImage makes it easy to add placeholder images to common scenarios and helps keep the user interface free of blank spaces. With easy support for WPF, Silverlight, and Windows Phone, you can add it to pretty much any XAML-based application!

 

[Click here to download the PlaceImageDemo project which includes PlaceImage.cs and sample applications for WPF, Silverlight, and Windows Phone.]

 

Notes:

  • Just like Image, PlaceImage has properties for Source, Stretch, and StretchDirection (the last being available only on WPF). PlaceImage's additional PlaceholderSource property is used just like Source and identifies the placeholder image to be displayed before the Source image is available. (So set it to a local image!)

  • Changes to the Source property of a loaded Image immediately clear its contents. Similarly, changing the Source of a loaded PlaceImage immediately switches to its placeholder image while the new remote content loads. You can trigger this behavior in the sample application by clicking any kitten.

  • Because the Silverlight version of the demo application references web content, it needs to be run from the PlaceImageDemoSL.Web project. (Although running PlaceImageDemoSL will show placeholders, the kitten pictures never load.) The MSDN article URL Access Restrictions in Silverlight has more information on Silverlight's "cross-scheme access" limitations.

  • Control subclasses typically live in a dedicated assembly and define their default Style/Template in Generic.xaml. This is a great, general-purpose model, but I wanted PlaceImage to be easy to add to existing projects in source code form, so it does everything in a single file. All you need to do is include PlaceImage.cs in your project, and PlaceImage will be available in the Delay namespace.

  • The absence of the StretchDirection property on Silverlight and Windows Phone isn't the only platform difference PlaceImage runs into: whereas Silverlight and Windows Phone offer the handy Image.ImageOpened event, WPF has only the (more cumbersome) BitmapSource.DownloadCompleted event. The meaning of these two events isn't quite identical, but for the purposes of PlaceImage, they're considered equivalent.

Invisible pixels are just as clickable as real pixels! [Tip: Use a Transparent brush to make "empty" parts of a XAML element respond to mouse and touch input]

Tip

Use a Transparent brush to make "empty" parts of a XAML element respond to mouse and touch input

Explanation

I got a question yesterday and thought the answer would make a good addition to my Development Tips series. As you probably know, WPF, Silverlight, and Windows Phone support a rich, hierarchical way of laying out an application's UI. Elements can be created in XAML or in code and respond to input by firing the relevant events (MouseLeftButtonDown, Click, etc.). Input events bubble from the element "closest" to the user all the way up to the root element (stopping if an event is marked Handled). Every now and then someone finds that an element they expect to be getting input is not (and they've made sure none of its children are "eating" the event). The most common reason is that the element doesn't have any pixels for the user to click on! For example, in a 100x100 panel containing a short message, only the text pixels are considered part of the panel and respond to mouse input - everything else passes "through" the empty area and bubbles up to the parent. This behavior enables the creation of elements with any shape, but sometimes it's not what you want. Fortunately, it's simple to get empty parts of an element to respond to input: just draw some pixels! And while a Brush of any color will do the trick, painting with Transparent pixels is a fantastic way to keep empty space looking empty while also being clickable!

Good Example

<Grid
    Background="Transparent"
    MouseLeftButtonDown="Grid_MouseLeftButtonDown">
    <TextBlock
        Text="You can click anywhere in the Grid!"
        HorizontalAlignment="Center"
        VerticalAlignment="Center"/>
</Grid>

More information

"Sort" of a follow-up post [IListExtensions class enables easy sorting of .NET list types; today's updates make some scenarios faster or more convenient]

Recently, I wrote a post about the IListExtensions collection of extension methods I created to make it easy to maintain a sorted list based on any IList(T) implementation without needing to create a special subclass. In that post, I explained why I implemented IListExtensions the way I did and outlined some of the benefits for scenarios like using ObservableCollection(T) for dynamic updates on Silverlight, WPF, and Windows Phone where the underlying class doesn't intrinsically support sorting. A couple of readers followed up with some good questions and clarifications which I'd encourage having a look for additional context.

 

During the time I've been using IListExtensions in a project of my own, I have noticed two patterns that prompted today's update:

  1. It's easy to get performant set-like behavior from a sorted list. Recall that a set is simply a collection in which a particular item appears either 0 or 1 times (i.e., there are no duplicates in the collection). While this invariant can be easily maintained with any sorted list by performing a remove before each add (recall that ICollection(T).Remove (and therefore IListExtensions.RemoveSorted) doesn't throw if an element is not present), it also means there are two searches of the list every time an item is added: one for the call to RemoveSorted and another for the call to AddSorted. While it's possible to be a bit more clever and avoid the extra search sometimes, the API doesn't let you to "remember" the right index between calls to *Sorted methods, so you can't get rid of the redundant search every time.

    Therefore, I created the AddOrReplaceSorted method which has the same signature as AddSorted (and therefore ICollection(T).Add) and implements the set-like behavior of ensuring there is at most one instance of a particular item (i.e., the IComparable(T) search key) present in the collection at any time. Because this one method does everything, it only ever needs to perform a single search of the list and can help save a few CPU cycles in relevant scenarios.

  2. It's convenient to be able to call RemoveSorted/IndexOfSorted/ContainsSorted with an instance of the search key. Recall from the original post that IListExtensions requires items in the list to implement the IComparable(T) interface in order to define their sort order. This is fine most of the time, but can require a bit of extra overhead in situations where the items' sort order depends on only some (or commonly just one) of their properties.

    For example, note that the sort order the Person class below depends only on the Name property:

    class Person : IComparable<Person>
    {
        public string Name { get; set; }
        public string Details { get; set; }
    
        public int CompareTo(Person other)
        {
            return Name.CompareTo(other.Name);
        }
    }

    In this case, using ContainsSorted on a List(Person) to search for a particular name would require the creation of a fake Person instance to pass as the parameter to ContainsSorted in order to match the type of the underlying collection. This isn't usually a big deal (though it can be if the class doesn't have a public constructor!), but it complicates the code and seems like it ought to be unnecessary.

    Therefore, I've added new versions of RemoveSorted/IndexOfSorted/ContainsSorted that take a key parameter and a keySelector Func(T, K). The selector is passed an item from the list and needs to return that item's sort key (the thing that its IComparable(T).CompareTo operates on). Not surprisingly, the underlying type of the keys must implement IComparable(T); keys are then compared directly (instead of indirectly via the containing items). In this way, it's possible to look up (or remove) a Person in a List(Person) by passing only the person's name and not having to bother with the temporary Person object at all!

 

In addition to the code changes discussed above, I've updated the automated test project that comes with IListExtensions to cover all the new scenarios. Conveniently, the new implementation of AddOrReplaceSorted is nearly identical to that of AddSorted and can be easily validated with SortedSet(T). Similarly, the three new key-based methods have all been implemented as variations of the pre-existing methods and those have been modified to call directly into the new methods. Aside from a bit of clear, deliberate redundancy for AddOrReplaceSorted, there's hardly any more code in this release than there was in the previous one - yet refactoring the implementation slightly enabled some handy new scenarios!

 

[Click here to download the IListExtensions implementation and its complete unit test project.]

 

Proper sorting libraries offer a wide variety of ways to sort, compare, and work with sorted lists. IListExtensions is not a proper sorting library - nor does it aspire to be one. :) Rather, it's a small collection of handy methods that make it easy to incorporate sorting into some common Silverlight, WPF, and Windows Phone scenarios. Sometimes you're forced to use a collection (like ObservableCollection(T)) that doesn't do everything you want - but if all you're missing is basic sorting functionality, then IListExtensions just might be the answer!

Something "sort" of handy... [IListExtensions adds easy sorting to .NET list types - enabling faster search and removal, too!]

If you want to display a dynamically changing collection of items in WPF, Silverlight, or Windows Phone, there are a lot of collection classes to pick from - but there's really just one good choice: ObservableCollection(T). Although nearly all the IList(T)/ICollection(T)/IEnumerable(T) implementations work well for static data, dynamic data only updates automatically when it's in a collection that implements INotifyCollectionChanged. And while it's possible to write your own INotifyCollectionChanged code, doing a good job takes a fair amount of work. Fortunately, ObservableCollection(T) does nearly everything you'd want and is a great choice nearly all of the time.

Unless you want your data sorted...

By design, ObservableCollection(T) doesn't sort data - that's left to the CollectionView class which is the officially recommended way to sort lists for display (for more details, please refer to the Data Binding Overview's "Binding to Collections" section). The way CollectionView works is to add an additional layer of indirection on top of your list. That gets sorted and the underlying collection isn't modified at all. This is a fine, flexible design (it enables a variety of other scenarios like filtering, grouping, and multiple views), but sometimes it'd be easier if the actual collection were sorted and the extra layer wasn't present (in addition to imposing a bit of overhead, working with CollectionView requires additional code to account for the indirection).

 

So it would be nice if there were a handy way to sort an ObservableCollection(T) - something like the List(T).Sort method. Unfortunately, ObservableCollection(T) doesn't derive from List(T), so it doesn't have that method... Besides, it'd be better if adding items to the list put them in the right place to begin with - instead of adding them to the wrong place and then re-sorting the entire list after the fact. Along the same lines, scenarios that could take advantage of sorting for faster look-ups would benefit from something like List(T).BinarySearch - which also doesn't exist on ObservableCollection(T).

All we really need to do here is provide custom implementations of add/remove/contains/index-of for ObservableCollection(T) and we'd have the best of both worlds. One way of doing that is to subclass - but that ties the code to a specific base class and limits its usefulness somewhat (just like Sort and BinarySearch for List(T) above). What we can do instead is implement these helper methods in a standalone class and enable them to target the least common denominator, IList(T), and therefore apply in a variety of scenarios (i.e., all classes that implement that interface). What's more, these helpers can be trivially written as extension methods so they'll look just like APIs on the underlying classes!

 

This sounds promising - let's see how it might work by considering the complete IList(T) interface hierarchy:

public interface IList<T> : ICollection<T>, IEnumerable<T>, IEnumerable
{
    T this[int index] { get; set; }         // Good as-is
    int IndexOf(T item);                    // Okay as-is; could be faster if sorted
    void Insert(int index, T item);         // Should NOT be used with a sorted collection (might un-sort it)
    void RemoveAt(int index);               // Good as-is
}
public interface ICollection<T> : IEnumerable<T>, IEnumerable
{
    int Count { get; }                      // Good as-is
    bool IsReadOnly { get; }                // Good as-is
    void Add(T item);                       // Needs custom implementation that preserves sort order
    void Clear();                           // Good as-is
    bool Contains(T item);                  // Okay as-is; could be faster if sorted
    void CopyTo(T[] array, int arrayIndex); // Good as-is
    bool Remove(T item);                    // Okay as-is; could be faster if sorted
}
public interface IEnumerable<T> : IEnumerable
{
    IEnumerator<T> GetEnumerator();         // Good as-is
}
public interface IEnumerable
{
    IEnumerator GetEnumerator();            // Good as-is
}

To create a sorted IList(T), there's only one method that needs to be written (add) and three others that should be written to take advantage of the sorted collection for better performance (remove, contains, and index-of). (Aside: If you know a list is sorted, finding the right location changes from an O(n) problem to an O(log n) problem. Read more about "big O" notation here.) The only additional requirement we'll impose is that the elements of the collection must have a natural order. One way this is commonly done is by implementing the IComparable(T) interface on the item class. Basic .NET types already do this, as do other classes in the framework (ex: DateTime, Tuple, etc.). Because this interface has just one method, it's easy to add - and can often be implemented in terms of IComparable(T) for its constituent parts!

 

So here's what the IListExtensions class I've created looks like:

static class IListExtensions
{
    public static void AddSorted<T>(this IList<T> list, T item) where T : IComparable<T> { ... }
    public static bool RemoveSorted<T>(this IList<T> list, T item) where T : IComparable<T> { ... }
    public static int IndexOfSorted<T>(this IList<T> list, T item) where T : IComparable<T> { ... }
    public static bool ContainsSorted<T>(this IList<T> list, T item) where T : IComparable<T> { ... }
}

You can use it to create and manage a sorted ObservableCollection(T) simply by adding "Sorted" to the code you already have!

 

[Click here to download the IListExtensions implementation and its complete unit test project.]

 

One downside to the extension method approach is that the existing List(T) methods remain visible and can be called by code that doesn't know to use the *Sorted versions instead. For Contains, IndexOf, and Remove, this is inefficient, but will still yield the correct answer - but for Add and Insert it's a bug because these two methods are likely to ruin the sorted nature of the list when used without care. Once a list becomes unsorted, the *Sorted methods will return incorrect results because they optimize searches based on the assumption that the list is correctly sorted. Subclassing would be the obvious "solution" to this problem, but it's not a good option here because the original methods aren't virtual on ObservableCollection(T)...

I'm not aware of a good way to make things foolproof without giving up on the nice generality benefits of the current approach, so this seems like one of those times where you just need to be careful about what you're doing. Fortunately, most programs probably only call the relevant methods a couple of times, so it's pretty easy to visit all the call sites and change them to use the corresponding *Sorted method instead. [Trust me, I've done this myself. :) ]

Aside: There's a subtle ambiguity regarding what to do if the collection contains duplicate items (i.e., multiple items that sort to the same location). It doesn't seem like it will matter most of the time, so IListExtensions takes the performant way out and returns the first correct answer it finds. It's important to note this is not necessarily the first of a group of duplicate items, nor the last of them - nor will it always be the same one of them! Basically, if the items' IComparable(T) implementation says two items are equivalent, then IListExtensions assumes they are and that they're equally valid answers. If the distinction matters in your scenario, please feel free to tweak this code and take the corresponding performance hit. :) (Alternatively, if the items' IComparable(T) implementation can be modified to distinguish between otherwise "identical" items, the underlying ambiguity will be resolved and things will be deterministic again.)

 

It's usually best to leverage platform support for something when it's available, so please look to CollectionView for your sorting needs in WPF, Silverlight, and Windows Phone applications. But if you end up in a situation where it'd be better to maintain a sorted list yourself, maybe IListExtensions is just what you need!

Don't shoot the messenger [A WebBrowserExtensions workaround for Windows Phone and a BestFitPanel tweak for infinite layout bounds on Windows Phone/Silverlight/WPF]

One of the neat things about sharing code with the community is hearing how people have learned from it or are using it in their own work. Of course, the more people use something, the more likely they are to identify problems with it - which is great because it provides an opportunity to improve things! This blog post is about addressing two issues that came up around some code I published recently.

 

The Platform Workaround (WebBrowserExtensions)

WebBrowserExtensions on Windows Phone

Roger Guess contacted me a couple of days after I posted the WebBrowserExtensions code to report a problem he saw when using it on Windows Phone 7 with the platform's NavigationService in a scenario where the user could hit the Back button to return to a page with a WebBrowser control that had its content set by the WebBrowserExtensions.StringSource property. (Whew!) Instead of seeing the content that was there before, the control was blank! Sure enough, I was able to duplicate the problem after I knew the setup...

My initial theory was that the WebBrowser was discarding its content during the navigation and not being reinitialized properly when it came back into view. Sure enough, some quick testing confirmed this was the case - and what's more, the same problem happens with the official Source property as well! That made me feel a little better because it suggests a bug with the platform's WebBrowser control rather than my own code. :)

The workaround I came up with for StringSource (and that was kindly verified by Roger) should work just as well for the official Source property: I created an application-level event handler for the Loaded event on the WebBrowser and use that event to re-apply the correct content during the "back" navigation. I updated the Windows Phone sample application and added a new button/page to demonstrate the fix in action.

If this scenario is possible with your application, please consider applying a similar workaround!

Aside: Although it should be possible to apply the workaround to the WebBrowserExtensions code itself, I decided that wasn't ideal because of the event handler: the entire StringSource attached dependency property implementation is static, and tracking per-instance data from static code can be tricky. In this case, it would be necessary to ensure the Loaded event handler was added only once, that it was removed when necessary, and that it didn't introduce any memory leaks. Because such logic is often much easier at the application level and because the same basic workaround is necessary for the official WebBrowser.Source property and because it applies only to Windows Phone, it seemed best to leave the core WebBrowserExtensions implementation as-is.
Further aside: This same scenario works fine on Silverlight 4, so it's another example of a Windows Phone quirk that needs to be worked around. (Recall from the previous post that it was already necessary to work around the fact that the Windows Phone WebBrowser implementation can't be touched outside the visual tree.) That's a shame because the scenario itself is reasonable and consistent with the platform recommendation to use NavigationService for everything. The fact that it seems broken for the "real" Source property as well makes me think other people will run into this, too. :(

[Click here to download the WebBrowserExtensions class and samples for Silverlight, Windows Phone, and WPF.]

 

The Layout Implementation Oversight (BestFitPanel)

Eitan Gabay contacted me soon after I posted my BestFitPanel code to report an exception he saw when using one of the BestFitPanel classes as the ItemsPanel of a ListBox at design-time. I hadn't tried that particular configuration, but once I did, I saw the same message: "MeasureOverride of element 'Delay.MostBigPanel' should not return PositiveInfinity or NaN as its DesiredSize.". If you've dealt much with custom Panel implementations, this probably isn't all that surprising... Although coding layout is often straightforward, there can be a variety of edge cases depending on how the layout is done. (For example: only one child, no children, no available size, nested inside different kinds of parent containers, etc..)

In this case, it turns out that the constraint passed to MeasureOverride included a value of double.PositiveInfinity and BestFitPanel was returning that same value. That isn't allowed because the MeasureOverride method of an element is supposed to return the smallest size the element can occupy without clipping - and nothing should require infinite size! (If you think about it, though, the scenario is a little wacky for BestFitPanel: what does it mean to make the best use of an infinite amount of space?)

There are two parts to my fix for this problem. The first part is to skip calling the CalculateBestFit override for infinite bounds (it's unlikely to know what to do anyway) and to Measure all the children at the provided size instead. This ensures all children get a chance to measure during the measure pass - which some controls require in order to render correctly. The second part of the fix is to return a Size with the longest width and height of any child measured when infinite bounds are passed in. Because children are subject to the same rule about not returning an infinite value from Measure, this approach means BestFitPanel won't either and that the Panel will occupy an amount of space that's related to the size of its content (instead of being arbitrary like 0x0, 100x100, etc.).

The combined effect of these changes is to fix the reported exception, provide a better design-time experience, and offer an more versatile run-time experience as well!

All BestFitPanels overlapped

[Click here to download the source code for all BestFitPanels along with sample projects for Silverlight, WPF, and Windows Phone.]

 

The more a piece of code gets looked at and used, the more likely it is that potential problems are uncovered. It can be difficult to catch everything on your own, so it's fantastic to have a community of people looking at stuff and providing feedback when something doesn't work. Thanks again to Robert and Eitan for bringing these issues to my attention and for taking the time to try out early versions of each fix!

I'm always hopeful people won't have problems with my code - but when they do, I really appreciate them taking the time to let me know! :)

"Those who cannot remember the past are condemned to repeat it." [WebBrowserExtensions.StringSource attached dependency property makes Silverlight/Windows Phone/WPF's WebBrowser control more XAML- and binding-friendly]

The WebBrowser control is available in Silverlight 4, Windows Phone 7, and all versions of WPF. It's mostly the same everywhere, though there are some specific differences to keep in mind when using it on Silverlight-based platforms. WebBrowser offers two ways to provide its content: by passing a URI or by passing a string with HTML text:

  1. If you have a URI, you can set the Source (dependency) property in code or XAML or you can call the Navigate(Uri) method from code.

    Aside: It's not clear to me what the Navigate(Uri) method enables that the Source property doesn't, but flexibility is nice, so I won't dwell on this. :)
  2. On the other hand, if you have a string, your only option is to call the NavigateToString(string) method from code.

    XAML and data-binding support for strings? Nope, not so much...

 

I'm not sure why all three platforms have the same limitation, but I suspect there was a good reason at some point in time and maybe nobody has revisited the decision since then. Be that as it may, the brief research I did before writing this post suggests that a good number of people have been inconvenienced by the issue. Therefore, I've written a simple attached dependency property to add support for providing HTML strings in XAML via data binding!

<phone:WebBrowser delay:WebBrowserExtensions.StringSource="{Binding MyProperty}"/>

As you can see above, this functionality is made possible by the StringSource property which is exposed by the WebBrowserExtensions class. It's a fairly simple attached property that just passes its new value on to the WebBrowser's NavigateToString method to do the real work. For everyone's convenience, I've tried to make sure my StringSource implementation works on Silverlight 4, Windows Phone 7, and WPF.

Aside: The StringSource property is read/write from code and XAML, but does not attempt to detect WebBrowser navigation by other means (and somehow "transform" the results into a corresponding HTML string). Therefore, if you're interleaving multiple navigation methods in the same application, reading from StringSource may not be correct - but writing to it should always work!

Aside: Things are more complicated on Windows Phone because the WebBrowser implementation there throws exceptions if it gets touched outside the visual tree. Therefore, if WINDOWS_PHONE is defined (and by default it is for phone projects), this code catches the possible InvalidOperationException and deals with it by creating a handler for the WebBrowser's Loaded event that attempts to re-set the string once the control is known to be in the visual tree. If the second attempt fails, the exception is allowed to bubble out of the method. This seems to work nicely for the typical "string in XAML" scenario, though it's possible more complex scenarios will require a more involved workaround.

My thanks go out to Roger Guess for trying an early version of the code and reminding me of this gotcha!

 

To prove to ourselves that StringSource behaves as we intend, let's create the world's simplest RSS reader! All it will do is download a single RSS feed, parse it for the titles and content of each post, and display those titles in a ListBox. There'll be a WebBrowser control using StringSource to bind to the ListBox's SelectedItem property (all XAML; no code!), so that when a title is clicked, its content will automatically be displayed by the WebBrowser!

 

Here's what it looks like on Silverlight (note that the sample must be run outside the browser because of network security access restrictions in Silverlight):

WebBrowserExtensions on Silverlight

 

And here's the same code running on Windows Phone:

WebBrowserExtensions on Windows Phone

 

And on WPF:

WebBrowserExtensions on WPF

 

[Click here to download the WebBrowserExtensions class and the samples above for Silverlight, Windows Phone, and WPF.]

 

The StringSource attached dependency property is simple code for a simple purpose. It doesn't have a lot of bells and whistles, but it gets the job done nicely and fills a small gap in the platform. You won't always deal with HTML content directly, but when you do, StringSource makes it easy to combine the WebBrowser control with XAML and data binding!

Each one is the best - for different definitions of "best" [The BestFitPanel collection of layout containers provides flexible, easy-to-use options for Silverlight, WPF, and Windows Phone applications]

Just over a year ago, a couple of readers asked me about a WPF/Silverlight Panel that arranged things to make "best use" of available space without requiring the developer to set a bunch of stuff up in advance or know how many child elements there would be. Interestingly, this is not a scenario the default Panel implementations handle particularly well...

  • Grid [WPF/SL/WP] is capable of pretty much anything, but requires the developer to explicitly specify how everything lines up relative to the rows and columns they must manually define.

  • StackPanel [WPF/SL/WP] arranges an arbitrary number of items in a tightly-packed line, but overflows when there are too many and leaves empty space when there are too few.

  • Canvas [WPF/SL/WP] provides the ultimate in flexibility, but contains absolutely no layout logic and pushes all that overhead onto the developer.

  • WrapPanel [WPF/SLTK/WPTK] flows its elements "book-style" left-to-right, top-to-bottom, but runs content off the screen when there's not enough room and can size things surprisingly unless you tell it how big items should be.

    Aside: When scrolling content that doesn't fit is acceptable, WrapPanel can be quite a good choice. And if you like the idea, but want something a little more aesthetically pleasing, please have a look at my BalancedWrapPanel implementation... :)
    Further aside: On the other hand, if you're looking for something more like a StackPanel but with multiple columns (or rows), you might instead be interested in my BandedStackPanel implementation.
  • DockPanel [WPF/SLTK] crams everything against the edge of its layout slot and leaves a big "chunk" in the center for whatever element is lucky enough to end up there.

  • UniformGrid [WPF] does okay at sensible layout without a lot of fuss - but its default behavior can leave a lot of blank space and so it's best if you tell it in advance how many items there are.

 

That said, please don't get me wrong: I'm not complaining about the default set of layout containers - I think they're all good at what they do! However, in the context of the original "just do the right thing for me" scenario, none of them quite seems ideal.

So when this question came up before, I mentioned I'd written some code that seemed pretty relevant, but that it was for Windows Forms and therefore didn't map cleanly to the different layout model used by Silverlight and WPF. Soon thereafter, I created a sample project to implement a "best fit" panel for Silverlight and WPF (and got nearly all the code written!) - but then found myself distracted by other topics and never managed to write it up formally...

 

Until now!

Today I'm sharing the three Panel classes I originally wrote for Silverlight and WPF, two abstract base classes they're built on, an extra Panel I wrote just for this post and a Windows Phone 7 sample application! (Because this code supports Silverlight 3, it works just as well on the phone as on the desktop.) Hopefully the extra goodness in today's release will offset the delay in posting it... :)

 

The foundation for everything, BestFitPanel is an abstract base class that implements MeasureOverride and ArrangeOverride to arrange its children in a grid that's M columns wide and N rows high. What's nice is that the values of M and N are left to subclasses to define by overriding the CalculateBestFit method. Therefore, a subclass only needs to worry about columns/rows and the base class only needs to worry about handling layout.

 

MostBigPanel is a BestFitPanel subclass that figures out which values of M and N maximize the length of the smaller dimension (be it width or height) of each item. In other words, it avoids long, skinny rectangles in favor of more evenly proportioned ones.

MostBigPanel

 

MostFullPanel is a BestFitPanel subclass that maximizes the total area occupied by the Panel's children. Specifically, an arrangement without any empty cells will be preferred over one with an empty cell or two - even if the shape of the resulting items is less balanced.

MostFullPanel

 

Sometimes it's nice to optimize for the "shape" of individual items - and for that there's the BestAnglePanel abstract base class which chooses the combination of M and N that yields items with a diagonal closest to some angle A determined by the GetIdealAngle override.

 

MostSquarePanel is a BestAnglePanel subclass that uses a value of 45° for A and therefore prefers arrangements where items are closest to being square.

MostSquarePanel

 

MostGoldenPanel, on the other hand, is a BestAnglePanel subclass that uses a value for A that matches that of a horizontally-oriented golden rectangle. Golden rectangles are said to be among the most aesthetically pleasing shapes, and this class makes it easy to create layouts based around them.

MostGoldenPanel

 

Of course, there are very few values of M and N to choose from, so it's not uncommon that all the implementations above choose the same values. The interesting differences tend to show up at various "special" sizes where each BestFitPanel selects a different layout. This is why the sample application allows you to enable all the panels at once: the sample content is translucent, so you can see where things differ and how each implementation is handling a particular configuration. I made sure all the arrangements above were unique - here's how it looks when they're all shown at once:

All BestFitPanels overlapped

 

For a real-world example of BestFitPanel in action, I've adapted the "ImageLoading" sample from my Windows Phone 7 PhonePerformance project to use MostBigPanel (which is what I would have used if I'd written this post beforehand!). If you're not familiar with that sample, it finds all the followers of an arbitrary Twitter account and shows their images. Because it's impossible to know in advance how many followers an account has, trying to use one of the "in-box" Panel implementations is likely to be tricky or require writing code to configure things at run-time. But BestFitPanel makes this scenario easy by automatically showing all the items and optimizing for the most important attribute ("bigness" in this case). Here's the same code/XAML with different numbers of followers (400, 200, and 100) to show how things "just work":

BestFitPanel with 400 items BestFitPanel with 200 items BestFitPanel with 100 items

 

[Click here to download the complete source code for all the BestFitPanels along with sample projects for Silverlight, WPF, and Windows Phone 7.]

 

The concept of a reusable, container-agnostic Panel for layout is tremendously powerful. The "stock" implementations for Silverlight, WPF, and Windows Phone are all quite useful, but sometimes you'll find that writing a custom Panel is the only way to get exactly the layout you're looking for. Fortunately, layout code is pretty straightforward - and classes like BestFitPanel and BestAnglePanel make it even easier. So the next time you're looking for a flexible container that works sensibly without requiring a bunch of prior knowledge or hand-holding, I hope you'll remember this post and consider using a BestFitPanel - or a custom subclass! :)

"Your feedback is important to us; please stay on the line..." [Improving Windows Phone 7 application performance is even easier with these LowProfileImageLoader and DeferredLoadListBox updates]

A few months ago I began a similar post about LowProfileImageLoader/DeferredLoadListBox updates by saying:

Windows Phone 7 applications run on hardware that's considerably less powerful than what drives typical desktop and laptop machines. Therefore, tuning phone applications for optimum performance is an important task - and a challenging one! To help other developers, I previously coded and blogged about two classes: LowProfileImageLoader (pushes much of the cost of loading images off the UI thread) and DeferredLoadListBox (improves the scrolling experience for long lists). These two classes can be used individually or together and have become a regular part of the recommendations for developers experiencing performance issues.

 

In the time since, I've continued to hear from people who are benefitting from LowProfileImageLoader and DeferredLoadListBox - and the code has even been incorporated into the WP7Contrib project! Along the way, I've also collected some great feedback, so I recently dedicated time to make a few improvements:

PhonePerformance List Scrolling sample
  • The most significant change is that I've removed the use of the UIElement.TransformToVisual platform-level method from DeferredLoadListBox because it has proven to be unreliable on Windows Phone 7 by throwing exceptions unexpectedly. Because this is not the first time I've had to fix crashes due to random ArgumentExceptions ("The parameter is incorrect."), I recommend not using the TransformToVisual method in Windows Phone 7 applications until/unless the underlying problem is fixed. In the meantime, it has been my experience that the LayoutInformation.GetLayoutSlot method can often be used as a substitute with just a little bit of extra effort.

    I'd like to thank Tore Lervik, Baldelli Gabriele, and Holger Schmeken for reporting this problem.

    Aside: Another time I had to remove TransformToVisual was for the Silverlight for Windows Phone Toolkit's ContextMenu control. (This fix was part of the November 2010 release).
  • I've previously explained why DeferredLoadListBox requires every container to have a height (note: each height can be different!). However, there are some scenarios where the Windows Phone 7 platform will report ActualHeight to be 0 for a container even though its height has been explicitly and correctly set (ex: via ItemContainerStyle). (Note: This seems to occur most often during scrolling.) Fortunately, I found an easy workaround that appears to resolve this problem in cases where the platform is misbehaving: a call to the UpdateLayout API is sufficient to correct the value of ActualHeight.

    I'd like to thank Rich Griffin and Michael James for reporting this problem.

  • LowProfileImageLoader originally used a Queue to implement "first in, first out" (FIFO) behavior of the image downloads it performs. This is a "fair" implementation and is ideal for slowly scrolling up/down a list that uses LowProfileImageLoader and DeferredLoadListBox together. However, for the scenario of quickly scrolling such a list in a single direction, FIFO behavior means the images you see on the screen will be among the last to load. The "obvious" fix is to switch from a Queue to a Stack which gives "last in, first out (LIFO) behavior instead. But while that's better for the second scenario, it's worse for the first one - and it leads to a weird visual effect in apps like my ImageLoading sample (part of the download) because the "wall" of images loads bottom-to-top instead of "top-to-bottom" as people expect.

    Clearly, there's no perfect answer here, so the solution is to do well on average! The classic way of amortizing unpredictable cost is to introduce randomness (ex: the QuickSort algorithm) - so instead of processing FIFO or LIFO, LowProfileImageLoader now works through its queue of pending work in random order. As a result, both the fast and the slow scrolling scenarios show images quickly and the application appears more responsive overall!

    Aside: The way I've implemented randomization is a slight variation of the solution to a classic programming puzzle: How do you sort a deck of N cards in linear time and constant space? If you haven't seen this one before, take a minute to think about it before following this link to a description of the Fisher-Yates/Knuth shuffle.
  • Though I initially meant for LowProfileImageLoader and DeferredLoadListBox to be used together, there's no reason LowProfileImageLoader can't be used on its own. In fact, I previously ensured that it works fine when used with the default ListBox/VirtualizingStackPanel combination. However, when the user is scrolling such a list very quickly, the default container recycling behavior means there will be multiple data bindings applied to a particular container in rapid succession. Every one of these will enqueue a request for LowProfileImageLoader to download the corresponding image - but only the most recent one matters. Any previous requests are "stale" and although it's safe to satisfy them, it's also unnecessary. Therefore, I've made a change with this update to detect stale requests and discard them before making an expensive web request on their behalf. This difference doesn't matter in non-virtualizing scenarios, but for virtualizing scenarios the amount of unnecessary work it saves can quickly add up!

  • Another consequence of using LowProfileImageLoader in the presence of container recycling is that re-used Image elements kept their old content until new content had been downloaded. This could lead to temporarily misleading UI where images show up alongside content they aren't associated with. It happens because LowProfileImageLoader didn't previously "null-out" the Source property when a new request was made. I've modified the code so it does now - and the virtualizing experience is nicer because of it.

  • When implementing the worker thread logic for LowProfileImageLoader, I intended for it to process WorkItemQuantum number of items each time through the loop until the queue of requests was exhausted. I wrote the following code:

    for (var i = 0; (i < pendingRequests.Count) && (i < WorkItemQuantum); i++)

    I'd like to thank Ashish Gupta for pointing out a bug here; what I meant was:

    for (var i = 0; (0 < pendingRequests.Count) && (i < WorkItemQuantum); i++)

    Coding errors in loops can cause serious problems if they result in an attempt to process too many or too few items. I got lucky here because there's no functional bug due to the original typo - the only downside is that performance might be a little worse because it takes a couple of extra passes through the loop to complete once the count drops below WorkItemQuantum. Fortunately, the value of WorkItemQuantum is only 5, so the real-world impact of this is minimal. However, the whole point of this code is to help improve performance, so I've fixed the oversight. :)

  • And finally, because I recently became a NuGet publishing "expert", I've created a package for the PhonePerformance assembly to make it easy to reference for all the NuGet fans out there. It contains the same binary you'd download below, but it contains only the assembly (and its XML IntelliSense file) - the three sample projects are available only with the ZIP download. This split seems like a reasonable compromise to me: reference from the NuGet gallery if you know what you're doing and just need to add the binary to your project - or - read the relevant blog posts and download the samples if you're getting started.

 

[Click here to download the compiled PhonePerformance assembly, sample applications, and full source code for everything.]

-OR-

[Click here to visit the NuGet gallery page for a package containing the PhonePerformance assembly.]

 

Windows Phone 7 developers must pay attention to performance because otherwise it's easy to end up with a slow, badly-behaved application. The PhonePerformance assembly focuses on two common scenarios (image loading and list scrolling) and attempts to improve upon the default experience by making it easy to avoid known problem areas. As with any performance technique, results can vary greatly depending on the specifics of each scenario, so it's important to take measurements and test everything on real phone hardware.

Many developers have told me they had success with the PhonePerformance assembly - I hope you do, too! :)