0

I have an application that loads some objects and displays them in a grid. One of those objects is a preview image which could be either a local image file or an image file on a web location. Right now it is working but the performance isn't very good when scrolling because whenever a new item scrolls into view it has to load the preview which takes a second or two.

What I am trying to accomplish is that the box for the preview would show up and start loading the preview on a background thread when it is scrolled into view. When the image is loaded it would notify (via property change event in the view model) and the image would come into place. This way the UI remains responsive and the preview is just blank until it loads and then it shows up. I have the getter for the bound property starting the backgroundWorker if the image isn't already cached, and the worker routine is as follows (_previewCache is the backing property for the bound preview):

    void bw_LoadPreview_DoWork(object sender, DoWorkEventArgs e)
    {
        BitmapImage _tempCache = new BitmapImage(new Uri(PreviewImagePath, UriKind.RelativeOrAbsolute));
        if (_tempCache.CanFreeze)
        {
            _tempCache.Freeze();
            Dispatcher.CurrentDispatcher.Invoke((Action)(delegate { _previewCache = _tempCache; }));
        }
    }

This seems to work pretty well on local files, though it takes a little longer than I would expect for the images to appear, but the UI remains responsive. However when the image is a web path, it always ends up as _tempCache.CanFreeze = false so it skips it and doesn't load. If I try to do the invoke without freezing, it says it can't use the object because it's owned by a different thread.

What am I missing? How do you load a web based image this way? Or is there a better way to approach this issue that I'm not seeing? Any help is greatly appreciated.

sfaust
  • 2,089
  • 28
  • 54
  • Where are you setting the BitmapImage downloaded from the web to your Image property in the ViewModel? Ideally is should be in the Complete handler of your background thread. – bit Apr 07 '15 at 06:07
  • BitmapImage already loads a remote image from a web Uri asynchronously. So there should be no need to use a background thread. See http://stackoverflow.com/a/16041810/1136211 – Clemens Apr 07 '15 at 07:10
  • @bit the _previewCache variable is the backing variable that is returned by the ViewModel property, so technically it's being set in the DoWork handler, then the worker completed handlers calls OnPropertyChanged... – sfaust Apr 07 '15 at 15:39
  • @Clemens I didn't realize that with BitmapImage, does it load async from local locations too? This property could be either a local location or a web location. It seems like the way I set it up works for local but can't be frozen for web locations... It seemed like it was lagging pretty bad when loading the images so I assumed it was the load process but maybe there is something else in my code that is lagging, I will look back at it again and see if there is anything else that would cause it. – sfaust Apr 07 '15 at 15:41
  • Then set the StreamSource property as shown in [this answer](http://stackoverflow.com/a/16041810/1136211). WebClient.DownloadData should also work with local Uris. Or use a FileStream for local files. – Clemens Apr 07 '15 at 15:52

0 Answers0