There's no substitute for customer feedback! [Improving Windows Phone 7 application performance now a bit easier with LowProfileImageLoader and DeferredLoadListBox updates]
**
This blog has moved to a new location and comments have been disabled.
All old posts, new posts, and comments can be found on The blog of dlaa.me.
See you there!
Comments
Anonymous
October 05, 2010
Thanks, looking forward to checking the latest version when I get home tonight. The OnApplyTemplate fix is something that I also hacked in myself. I didn't report it as I thought that I was just doing something wrong in the order I was loading things.Anonymous
October 24, 2010
Hi, Does DeferredLoadListBox work in pivot control? I am noticing some odd behavior with it. It seems to hang and make things load show when scrolling from one pivot item to the next.Anonymous
October 25, 2010
Zeus, I haven't specifically tried that scenario, but this is also the first I've heard of it being a problem, so maybe it's unique to your scenario. What you might do is create a new project and try to reproduce the problem there - reducing everything to its simplest form can often help identify the source of a problem like this. If you're still seeing this behavior in a simplified project, please get in touch with me via the "Email Blog Author" link on this page and I can have a look. Thanks!Anonymous
November 26, 2010
For several time in my test app, I encountered the same problem of System.Exception was unhandled in the file LowProfileImageLoader.cs at Ln 155 var response = responseState.WebRequest.EndGetResponse(pendingResponse); Any suggestions to resolve or work around it. Thanks very much.Anonymous
November 28, 2010
info815, As you can tell from the comment in the catch clause of that block, instances of WebException are expected when the file couldn't be downloaded, etc.. If you're running with first chance exceptions enabled, you may simply be hitting an instance of that. But if you're really seeing instances of Exception itself, it might be interesting to see the message and stack trace contained within to get an idea of what might be causing this. If you're able to share those, that could be quite helpful. Thanks!Anonymous
January 23, 2011
Hi, first of all thanks for releasing this. It does make a noticeable difference in performance. I am encountering a weird issue. I'm using the listbox in a user control that is within a pivot. However intermittently the application crashed throwing the "All containers must have a Height set (ex: via ItemContainerStyle), though the heights need not all need to be the same." exception. However this is said, and when you inspect the height property it has a value but the actual height doesn't. Do you have any ideas on what would be causing this? I have read that "ActualWidth and ActualHeight are calculated based on the Width/Height property values and the layout system. There is no guarantee as to when these values will be "calculated"." Which is why I'm guessing this error doesn't always occur for me. I was wondering whether the UnmaskItemContent needs to be called as an action using the Dispatcher?Anonymous
January 23, 2011
The comment has been removedAnonymous
January 24, 2011
I implemented a retry counter like you suggested, after many attempts at trying to reproduce the issue it appears having a retry counter is enough to resolve the issue. In my testing it appears just trying it 1 to 2 more times is enough. I now only throw an exception if the ActualHeight is 0 and the retry counter is greater than 2. You do notice a very slight pause in the UI rendering however as this error only occurs occasionally it seems a plausible and passable workaround. It's worth noting that I have a global retry counter, I considered one per item you try to unmask however it appears that a global one is more than enough as updates don't occur that frequently.Anonymous
January 24, 2011
Michael James, Great information - thanks a lot for the update!Anonymous
January 27, 2011
"So in lieu of a reliable way to detect the cache state of individual images (I'm open to suggestions, by the way!)" IIRC WebClient has a download can be forced to only use cached stuff. But of course WebClient is async as well.. But maybe this can be used as a starting point...Anonymous
January 27, 2011
Martin, That's a really interesting idea! What I'd really like is a way to tell if each image is in the cache or not - and I'm concerned the technique you point out might force the code to make a cache-only web request which is unnecessary/wasteful when it succeeds and delay-inducing when it fails. Ick. :( You may be onto something here, but it's not quite the clean WebClient.IsImageCached(...) method I might prefer... :)Anonymous
March 09, 2011
David, I just implemented the DeferredLoadListBox and it gives an amazing performance compared to a ListBox. However, my layout depends on Items in the ListBox with different Heights (Text-Blocks with varying length and wordwrapping). I'd even go as far and calculate the Height on my own but couldn't find an example on how to do. The Items in the DeferredLoadListBox are not controlls and therefore don't have an height? I also couldn't find any examples out there... Thanks in advance for some tips where to look.Anonymous
March 10, 2011
Arne Schmid, One way of doing this is to subclass and override the GetContainerForItemOverride method on (DeferredLoad)ListBox - that's your chance to customize the ListBoxItem container that gets automatically generated and you can assign a Height there (with full knowledge of the corresponding model object which will be its DataContext). For some background on how containers work with ItemsControl subclasses, here's a good post to read: drwpf.com/.../itemscontrol-g-is-for-generator Hope this helps!Anonymous
March 20, 2011
The comment has been removedAnonymous
March 21, 2011
Nadeem, Sorry for the confusion! GetContainerForItemOverride is the place to provide a custom container type (or just customize the default one), but PrepareContainerForItemOverride is the method I was thinking of when I talked about access to the container and the object for relevant customizations: msdn.microsoft.com/.../system.windows.controls.itemscontrol.preparecontainerforitemoverride(v=VS.95).aspx With that mistake of mine cleared up, I think you'll have an easier time of this. :)Anonymous
March 21, 2011
Thanks a lot David. I have a good idea of how to do it now. ...I should have spent more time digging for the right method but sometimes a person get's overwhelmed with the sheer amount of new info to digest :-) Regards, NadeemAnonymous
April 07, 2011
Hi David, I have tried to use the LowProfileImageLoader in a ListBox and WrapPanel as the ListBox's ItemsPanel but my image was not loaded at all :( Do you have any idea why? Regards, VeriAnonymous
April 08, 2011
Veri, Nothing about switching to a different ItemsPanel should affect how LowProfileImageLoader works. You might try switching back to the default ItemsPanel to see if the problem remains - if so, then it's probably something else (like a broken Binding?). Alternatively maybe try WrapPanel+LowProfileImageLoader outside a ListBox to verify that works okay.Anonymous
April 18, 2011
Hi David, I have tried your suggestion but it still didn't work :( I have a few questions though:
- Do I have to use the DeferredListBox or can I use the default ListBox?
- Can I change the LowProfileImageLoader.UriSource to catch string instead of url? Regards, Veri
- Anonymous
April 18, 2011
Veri,
- You can definitely use LowProfileImageLoader with the default ListBox. The two classes work together, but are not tied together. :)
- I don't quite understand the question, but if you're asking if you could make UriSource a string-typed property instead of a Uri-typed property, that should work just fine (once you update the parts of the code that assume Uri). Hope this helps!
Anonymous
July 25, 2012
Thank you for this lib! Is there a way to fade in the downloaded image? I tried from ImageOpened but I discover here that it is not triggered :( Thanks for any help!Anonymous
July 25, 2012
Geobert, Please see the comments in this post for some information about ImageOpened: blogs.msdn.com/.../keep-a-low-profile-lowprofileimageloader-helps-the-windows-phone-7-ui-thread-stay-responsive-by-loading-images-in-the-background.aspx But you may be able to modify the code for LowProfileImageLoader itself to get the effect you want by adding in an Animation of the Image's Opacity property from 0->1. Hope this helps!Anonymous
August 30, 2012
The comment has been removedAnonymous
September 01, 2012
iglaweb, If there's a crash, you can usually find out what the exception was in the debugger and use that (plus the call stack) to figure out what went wrong. Sometimes it can help to turn on first chance exception handling in the debugg.r as well (a web search will say how to do that). Because my sample application works properly, I'm not sure offhand what would cause this - another thing to try would be incrementally commenting stuff out of your application until the problem goes away and using that to see what the specific cause might be. Hope this helps!Anonymous
January 14, 2013
Hi David, great stuff! Wouldn't it be a good idea to have an option to store the downloaded file in isolated storage for later use? And then automatically check whether the icon is already available in isolated storage and load it from there instead of the internet?Anonymous
January 15, 2013
Pete, Sure, that's a neat idea. Shawn Burke actually wrote a framework for that called AgFx: github.com/.../AgFx. You may want to check that out; my understanding is that it supports exactly the scenario you're interested in. Good luck!