views:

714

answers:

4

Hello, I have a WPF application that uses a component that sends a bitmap to my application as they become available, I receive those bitmaps in a delegate I pass to this component.

I created a new thread for this process and it works very well, the bitmaps comes as MemoryStream and I just create the BitmapSource object from this stream inside a Dispatcher.BeginInvoke method call. After I have the BitmapSource object, I add them to a StackPanel so the user can see a queue of images available to work. So far so good...

The problem is that those bitmaps are quite big, like 3000x2000+ pixels, and it takes about 50~ms to create these bitmaps and add to the queue, and when this code is executed, the onde inside the BeginInvoke call, it blocks the UI for this time, causing a very annoying behavior, (to reproduce this, just call Thread.Sleep(50) every 5 seconds).

How can I fix this so the user is always responsive?

thanks!

+1  A: 

Two possibilities come to mind quickly.

The first is to use a BackgroundWorker to perform the transformation of the MemoryStream to a Bitmap.

the Second is to pass off that transformation to a ThreadPool.

Stephen Wrighton
I second the second suggestion (threadpool).
unforgiven3
A: 

While not an entirely satifsfactory answer for you, I would suggest you listen to this Hanselminutes podcast with Ian Griffiths as it covers a very similar program and the proper way to architect it to get the performance you are looking for.

Some specifics may be found on Ian's blog: http://www.interact-sw.co.uk/iangblog/

Rob Allen
+4  A: 
Oren Trutner
+1  A: 

Really all you need to do is set the IsAsync to True on your binding to the image. I would however recomend using a PriorityBinding and preparing some form of default image that the user can see so they know it isn't fully loaded.

<StackPanel>
 <Image>
  <Image.Source>
   <PriorityBinding>
    <Binding Path="SlowImage"
       IsAsync="True" />
    <Binding Path="DefaultImage" />
   </PriorityBinding>
  </Image.Source>
 </Image>
</StackPanel>


public partial class Window1 : Window, INotifyPropertyChanged
{

 public Window1()
 {
  InitializeComponent();

  DefaultImage = new BitmapImage(new Uri("http://stackoverflow.com/content/img/so/logo.png"));

  SlowImage = new BitmapImage(new Uri("http://serverfault.com/content/img/sf/logo.png"));

  this.DataContext = this;
 }

 private BitmapImage myDefaultImage;
 public BitmapImage DefaultImage
 {
  get { return this.myDefaultImage; }
  set
  {
   this.myDefaultImage = value;
   this.NotifyPropertyChanged("Image");
  }
 }

 private BitmapImage mySlowImage;
 public BitmapImage SlowImage
 {
  get
  {
   Thread.Sleep(5000);
   return this.mySlowImage;
  }
  set
  {
   this.mySlowImage = value;
   this.NotifyPropertyChanged("SlowImage");
  }
 }

 #region INotifyPropertyChanged Members

 private void NotifyPropertyChanged(String info)
 {
  if (PropertyChanged != null)
  {
   PropertyChanged(this, new PropertyChangedEventArgs(info));
  }
 }

 public event PropertyChangedEventHandler PropertyChanged;

 #endregion
}
rmoore
where did you find this NotifyPropertyChanged?
Schwertz
NotifyPropertyChanged is an implementation of the INotifyPropertyChanged interface that handles updating the UI for you: http://msdn.microsoft.com/en-us/library/ms229614.aspx I'll update my answer to include the whole window class.
rmoore
got it thanks!
Schwertz