GWI Mobile
Login   Search
Skip Navigation Links
Home
GWI Mobile Blog
Windows Phone News
Windows Phone Apps
Skip Navigation Links>Windows Phone News

Listbox, Why Art Thou Blanking?

One of the biggest performance changes for developers using Silverlight in Mango (WP 7.5) is off-thread input for ListBox. In a nutshell this basically means that all any flick or pan a user makes on a ListBox is handled by a dedicated thread, the Direct Manipulation (DM) thread, instead of the UI thread. By connecting the DM thread to the Compositor thread (that’s the one that does all the drawing to the screen independent of the UI thread) we have a ListBox that moves smoothly even when the UI thread is completely blocked.

Unfortunately this also comes with a price – the ListBox is now so responsive and moves so fast that the Listbox can run out of content to display to the user as the user is flicking, and blank – basically drawing nothing except for an updated ScrollBar (so the user knows he’s still moving in the ListBox, but it doesn’t help much) and the background while the UI thread scrambles to bring in new items to fill up the holes.

My ListBox isn’t blanking, why do I care about this blog post?

You care because you care about your users. You’re the kind of dev who knows that even though he’s got a great, powerful phone, not everyone does. You care because you are proud to call yourself a developer. You care because… ok, back to reality.

With the release of Tango, Windows Phone is now supported on lower powered machines which often have slower hardware and less memory, so even though your device shows no blanking, others may see blanking, especially if they’re rocking a new, lower powered, Tango phone. This post will help give you the tools that let your app run smooth, with hardly any blanks, even on those phones.

My ListBox is not blanking, but it’s really jerky during scroll

Holy Smokes Batman! Jerky scrolling is all but eliminated in the new ListBox, even for WP7 apps – are you sure you’re using it? There’s a good chance you’re using the original LongListSelector (LLS) from the toolkit, which doesn’t auto-update when you move your project to Mango. To take full advantage of the new ListBox improvements you need to download the latest toolkit from http://silverlight.codeplex.com and update to the new LLS which is based on the platform’s ListBox.

Why does blanking occur: the nitty gritty

There are a couple of common code / design reasons that cause a ListBox to blank, but in general it all boils down to the amount of time it takes to bring in a new item. The ListBox maintains a one screen buffer of items in each direction which moves with the user’s viewport as they scroll around. If the ListBox can’t fill that buffer in the direction of the scroll fast enough, you get blanking.

Diagram 1: In a stationary world, when there is no scrolling going on, the user will be looking at the center screen and there will be buffered items waiting to be shown in both directions

Filling the buffer takes a few steps, namely creating an Item Container (if a suitable one from the excess buffer in the other direction doesn’t already exist) and Data Binding the new item’s content (which kicks off the Measure pass). All of these updates occur on the UI thread and they all happen at once (not item by item) so if a flick is fast and the ListBox realizes that it needs to draw a full screen worth’s of items it will block the UI thread while it does just that.

Diagram 2: As the user moves downwards we balance the buffers by transferring the excess buffer from the top buffer (red) to the bottom buffer and re-databind it to the new data, maintaining 1 screen of buffer in each direction.

But if the user flicks again while the UI thread is blocked bringing in buffer items, we’ll get even more out of sync and move completely out of our buffer space – since there is nothing in the Control to draw (remember, the ListBox is still scrambling on the UI thread to bring the new items in, it’s just too slow) you just get the background, i.e blankness.

If there’s nothing to draw, why is the ListBox still moving? Or, look at it from another angle:

As we mentioned earlier, scrolling is now off-thread, so from the Compositor’s point of view it’s moving the ListBox and everything in it, the problem is that the UI thread hasn’t stuck anything in it (at that position) yet, so we blank.

Diagram 3: Fast flicking a few times get you into this situation, where we have excess buffer above which we are trying to move downwards, but because there is so much of it and the UI thread is blocked trying to bring these items in we don’t finish in time and the user sees blankness (black) until the items are ready, at which time they simply appear.

So why is *my* ListBox blanking? And how do I fix it?

Let’s run through a couple of common reasons why ListBoxes blank, with some proposed solutions to each one.

1. Using ValueConverters in your template

ValueConverters are great – they allow you to transform your data on the fly as they are being DataBound into your items. Unfortunately they incur a UI thread cost – we need to transition from Silverlight into User Code, run your converter and then return. If your converter is heavy or you’re using lots of them in your template, then this will introduce blanking.

Question to ask yourself: does this code look like it can run in a trivial amount of time across all of the elements being brought in for a given frame? If not, you probably should explore a different way of doing the DataBinding. For example,you can have the object translate the values on population / property get time instead of using a converter - even though this may break your Data Model this can significantly reduce the DataBinding cost (and you could always wrap your object in a ViewModel).

2. Complex DataTemplates

When an item is moved from one buffer to another during a scroll, ListBox is usually smart enough to determine that this is the same kind of item and just update the data in the item. While this might sound cheap this dirties the item causing it to be remeasured. If your template is complex you will find that a lot of your time is wasted in Measure – remeasuring the layout of the control now that the data has been updated.

Fixing this is very per-scenario. Some general guidelines are to make sure to only use a container if you really need the options it provides – do you have a Grid within a Grid? Could you replace all of your Grids with a simple Canvas or maybe a StackPanel?

3. Decoding images on the UI thread

By default all images are decoded synchronously on the UI thread, so if you have something like this:

<Image Source=”{Binding ImageUrl}”/>

you're going to block the UI thread for however long it takes to decode your image. Luckily there’s an easy fix for this, change your template to read as follows:

<Image>
  <Image.Source>
    <BitmapImage UriSource="{Binding ImgUrl}" CreateOptions="BackgroundCreation"/>
  </Image.Source>
</Image>

Note that this does come with some caveats – older images will still show up until the new ones are loaded and the user may see a visual pop-in of the image when it is done loading, but these can all be worked around and massaged into a nice user experience that is not harmed by excessive image decode.

For further details see this blog post.

4. Using PrepareItemForContainerOverride to dynamically select a template

A simple list item is often times just not good enough – your app has an image item, a text item, a video item, a link item etc. etc. and you have a different template for each one of them. A common pattern is to use the ListBox’s PrepareItemForContainerOverride callback to dynamically change the container’s template based on what item is being databound.

Unfortunately, doing this can completely throw off the ListBox’s buffering technique – the ListBox sees that the container that it had in its buffer is not the type that you need and junks it, wasting even more time on the march to blankness.

So how do I solve this? Surprisingly enough, it is often cheaper to have all of your template parts in one large template (yes, yes, I know about point 2 above – keep reading!) with each mini-template collapsed if it does not apply. Since collapsed template items incur next to no cost during layout, they have next to no impact on run time (though there is a slightly larger memory cost).

And how do I get my different items to display on the different templates? Simple – databind to a new property on your classes which either has a type enumeration that runs through a value converter (ItemTypeToVisibility), these kinds of converters are often cheap, or wrap your class in a UI view model so that it has a property that returns the Visibility type directly.

5. Pulling data from [favorite heavy source] as part of your binding

The properties you bind to should have simple getters (setters is a different story) – always. If you have logic like this:

public int Rating
{
  get
  {
    <read from database>   
    - or -
    <read from IsoStore>
    - or -
    <parse out some XML>
    - etc -   
 
}
}


then you’re doing something wrong. This kind of logic is fine for a property that you know is only read very rarely, if at all, but if it’s in a ListBox then it most likely is going to be seen and you should be initializing the data up front.

Don’t get me wrong – you don’t need to load everything as you are pulling in 1000 items to your list, but you can certainly do it on a background thread as a deferred task kicked off in the constructor of your object. If your objects are really heavy and memory is becoming an issue then you have a few possible routes:

  • Implement a completely delayed load by hooking into the ListBox’s scroll amount or compression states and only loading more items when you get to the end of the list
  • Implement a DoubleLinkedObservableCollection, where each item in the collection knows about the next node (in each direction) and when it gets databound (based on one of the properties) it notifies X number of nodes on each side to make sure they all have their data ready to go. This should be done on a background thread, just don’t forget to Dispatch back to update any properties that raise a PropertyChanged event.

6. Cut down background work

With only one core any background thread can interfere with the smoothness of the UI thread. Although background threads get a much smaller time slice compared to the UI thread, enough of them vying for time will effectively starve the UI thread.

Diagram 4: Fictional time slice showing the effects of more background threads (not to scale)

Across any given slice of time, the UI thread will be allowed to run longer than any other thread, but is effectively running at the same priority, hence it is forced to yield to the background threads when its time is up. The more background threads, the longer it is before you get back to the UI thread so that it can complete its task.

Moral of the story? Be wise about the number of active background, especially in high stress scenarios. Stick to using a thread pool so that you can queue up your work without it all trying to run at the same time.

I’ve tried all the above, it’s still blanking and I only have a couple of screens of data – help!

If you find yourself blanking on a relative small set of data (approximately 3-5 screens), then it might be time for drastic measures. As mentioned above the cause for blanking is the amount of time it takes to bring in new items with new data as the user is scrolling, i.e. the virtualization overhead is the culprit. If you disable virtualization on your list, you’ll generate of all your items up front and scrolling will be blankless. To do this, add the following to your XAML:

<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel>
</StackPanel>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>

While making this change is relatively simple, the impact can be drastic – no more blanking, but it comes at a cost:

  1. Startup time for the Page increases – we now have to realize more items, so it’s going to take longer
  2. Memory – same as above, more items hanging around, larger memory cost

If you give it a try on a low end device and startup and memory look acceptable – then this is your magic bullet!

So what are we left with?

Hopefully at this point you have a non to minimally blanking list, which scrolls smoothly and generally delights your users! Have you run into any other pitfalls that you think others should be warned of? Let us know below!

Running into other, unrelated performance issues? Drop us a line and we'll see if we can focus on them in a future blog post (stay tuned for a "memory" series coming soon).

Memory Profiling - The Heap Summary View

In an earlier post we looked at how we can gain broad insight into an application scenario’s memory characteristics and how the graph and markers drew our attention to ranges of execution for further analyses. Recall that in the memory leak diagnosis case we chose to analyze only the time range over which we observed the increase in memory usage. Indeed, that is a key first step to the analysis: filtering the memory activity data by a time range. The Heap Summary view is the result of such filtering, and represents the population of the heap during the chosen time range.

Heap Summary View

The Heap Summary view presents, in tabular form, a demographic analysis of the population of the heap.

In human population demographics, data collection happens through a census as well as through a continuous update to registries that track births, deaths, migration of place of residence and the like. The data collection in the case of heap population demographics is no different. “Births” map to allocations, “deaths” map to objects’ memory collected by the GC, and “migration of place of residence” maps to the migration of objects between the Gen0 region of the heap and the Gen1 region. A census of the heap at the start of time range identifies all incumbent objects (i.e. that were in existence). Births, deaths, and migrations are updated continuously, and a final census at the end of the time range identifies all the objects that were retained. In order to have a consistent terminology, we refer to the incumbent objects at the start as objects that were “retained” at the start.

Managed Silverlight Visual elements (i.e. objects that go into the Silverlight visual tree) are not just plain old managed objects. These might be facades with backing native-implementations holding native memory and during the course of execution might create and hold on to texture memory. Casual use of such elements in code can even lead to subtle leaks. From this perspective, subsequent analysis can be made easier if Silverlight Visual elements were tracked and reported separately from plain old managed objects. And this is precisely how they are tracked and reported through the Heap Summary view. Continuing with the demographic analogy, such classification has precedent in social demographics where human populations have been classified on ethnicity.

Armed with this context, let us study the following Heap Summary view from the memory leak diagnosis case:

The shaded region across the graph and markers indicates the time range used as the filer.

The census at the start reports 5576 instances of managed type objects accounting for about 283 KB and 26 instances of Silverlight Visual elements accounting for about 13 KB. In terms of incumbency the plain old managed objects dominate.

The churn happening within the selected time range is reported as 10615 instances allocated (births) and 11590 instances collected (deaths), accounting for about 23 MB each. The counts and sizes are somewhat balanced and cancel each other out to an extent. And this is borne out by the census at the end for the managed objects; the census at the end reports 4601 instances of managed type objects accounting for about 223 KB, which is just a little lower than what we had at the start. However, it also reports 69 instances of Silverlight Visual elements accounting for about 4 MB now (up from 13KB at the start).

When we correlate this table with the graph, our suspicion is drawn towards the Silverlight visuals. Why did their count go up, and why are they accounting for so much more memory? Within the filtered time range, memory usage has been steadily increasing too. Could we be leaking memory? Could we be leaking some part of visual tree itself? And there even seem to be images being loaded along the way; might we be leaking their texture memory too? We wonder.

Clearly, the next lead to follow is to get more visibility into what are those “Retained Silverlight Visuals at End”.

Summary

The Heap Summary view presents, in tabular form, a demographic analysis of the population of the heap. Interpreting the data in the table and correlating it with the graph and markers by itself can be used to make educated guesses at what could potentially be the problem, but equally importantly it serves to inform the next step in the performance investigation, as we shall see.

Delivering Rich Mobile Web Experiences in Windows Phone 7.5 (ESPN.com Case Study)

The Windows Phone Browser team has a goal of delivering the best web browsing experience on a smartphone. This goal has many components within our team: from the UI of the browser, compatibility with a wide array of website layouts, and of course buttery-smooth rendering performance. However, even if we execute flawlessly on our end, we are missing a crucial piece - delivering a great web experience is fundamentally a partnership between our team and web developers. Achieving this goal means working together to ensure that your content and services are delightful for users to consume on Windows Phone.

We understand that web development resources are always limited as you keep up with the increasing traffic from mobile devices, and the elusive "write once, run everywhere" promise of web development has not perfectly materialized. However, with IE9 for Windows Phone 7.5, we took a big step in the direction of this promise. By sharing a codebase with IE9 for the PC, we achieved identical support for new web standards and pushed the envelope on real-world performance with industry-leading hardware acceleration. We wanted to hear about developing for IE9 on WP7.5 from web developers directly, so we decided to collect some feedback and share it on the blog.

ESPN.com recently deployed their premium web experience to Windows Phone, and we thought it would be great to hear what they had to say about developing for IE9 on Windows Phone. As a side note, ESPN started looking into supporting Windows Phone because of a simple request I made on their support page. Lots of folks on my team are sports fans and were asking me about the site's experience on WP7.5, so I just dropped ESPN a note like any user would. The message was quickly routed to the mobile site team; I have immense respect for ESPN’s responsiveness and the system they have place to address user feedback. Here's what Mike Marrone, technical lead, had to say about developing for IE9 on WP7.5:

Overall, it was an easy process. We support only WP7.5 and IE9 thanks to its very good CSS3/HTML5 support. We are in a convenient position of having an existing legacy mobile site that older devices can fallback to. Honestly, development for WP7.5 boiled down to a fairly basic process - IE9 on the PC, being nearly the same browser, was a great dev tool to get most of the way there before final QA on actual devices.

Some other more specific development notes:

  • The "display: box" CSS style is not supported on WP7.5. We use this in carousel experiences to transition elements left or right 100% of the viewport without having to programmatically determine the viewport size (which means the browser automatically updates the positioning upon device rotation, etc.). On WP7.5, we actually used a better alternative thanks to it being the only browser that currently supports the CSS "vw" unit (VERY useful).
    [Amin] See here and here for more information on vw units.
  • The bulk of our CSS differences between WP7.5 and other supported devices was with gradients. WP7.5 has an easy fallback with filters so it was not a big development issue.
    [Amin] See here for information on using Gradient Filters in IE9.
  • JavaScript touch events would be a nice addition.
    [Amin] We hear you, stay tuned!

We look forward to your continued great progress in mobile.

As you can imagine, this was music to our ears! We often use IE on the PC to investigate bugs, and it was great to hear that the tools work well for web development outside of our offices too. We appreciate the feedback (it will inform our plans for future releases) and welcome additional feedback through the comments below.

IE9 on Windows Phone is set up to support rich web experiences with great performance, and often all it takes is updating user-agent logic and using standards based (as opposed to vendor prefixed) HTML & CSS. ESPN invested a reasonable level of resources to do that and delivered a delightful experience to its users. I've definitely started to see the site pinned to Start around here, and I wouldn't be surprised if our senior managers are secretly checking ESPN during meetings.

Here's a before (left) and after (right) screenshot of the ESPN.com experience on Windows Phone 7.5. We want to say thanks to ESPN, and we look forward to seeing more rich experiences light up!

    

Special thanks to Krys Krycinski, Mike Marrone, and James Ballow at ESPN.

Amin Lakhani
Program Manager, Windows Phone

How many days until app gets tested by ms?

Hello

How many days did it take for your app until it got approved/tested?

Thanks

Error while registering developer device

Its showing device not registered with marketplace.Please return to developer portal for more information. (Error code :0x80040207).


==== "It ain't a bug,Its an undocumented feature" ====

IsolatedStorageSettings problems

I'm trying to add a string ("hello") to my IsolatedStorageSettings'.

IsolatedStorageSettings.ApplicationSettings.Add("myProperty", "hello");
IsolatedStorageSettings.ApplicationSettings.Save();
Problem is I keep getting the following error:

"ArgumentException was unhandled.

Value does not fall within the expected range."

It is indicating the "hello" string. My understanding is that a string is in fact an object, and since the Add-function's second parameter is an object this should work. But alas, no. I've googled the string as well, and seen many code-snippets adding a string or int or other simple variable as the second parameter, so I'm not sure what's going on here...

WOL client impossible?

Deal all, AFAIK Windows Socket interface is not available for WP7 so it is impossible to write a Wake On Lan client. Is this true? Anyone heard of a web based WOL service that can

a) relay the magic packet requests to my router
b) works fine with WP7?

Thanks,
Z


B

List Picker

Hi

 

I have a list picker i am using in my settings page when i click a list picker then select an item i would think it would automaticly display what i selected but it dosn't is ther code i need to add to display what was selected? if so i would asumn it would b in the selectionchanged event. culd someone post sample code or is there some setting to set to make it display this info?

Copyright 2011 GWI All Right Reserved.