How do you pass a BitmapImage from a background thread to the UI thread in WPF?

后端 未结 3 1850
-上瘾入骨i
-上瘾入骨i 2020-12-03 06:52

I have a background thread that generates a series of BitmapImage objects. Each time the background thread finishes generating a bitmap, I would like to show th

3条回答
  •  天命终不由人
    2020-12-03 07:44

    You need to do two things:

    1. Freeze your BitmapImage so it can be moved to the UI thread, then
    2. Use the Dispatcher to transition to the UI thread to set the GeneratedImage

    You'll need to access the UI thread's Dispatcher from the generator thread. The most flexible way to do this is to capturing the the value Dispatcher.CurrentDispatcher in the main thread and passing it into the generator thread:

    public void InitiateGenerateImages(List coordinates)   
    {
      var dispatcher = Dispatcher.CurrentDispatcher;
    
      var generatorThreadStarter = new ThreadStart(() =>
         GenerateImages(coordinates, dispatcher));
    
      ...
    

    If you know you will only use this within a running Application and that the application will only have one UI thread, you can just call Application.Current.Dispatcher to get the current dispatcher. The disadvantages are:

    1. You loose the ability to use your view model independently of a constructed Application object.
    2. You can only have one UI thread in your application.

    In the generator thread, add a call to Freeze after the image is generated, then use the Dispatcher to transition to the UI thread to set the image:

    var backgroundThreadImage = GenerateImage(coordinate);
    
    backgroundThreadImage.Freeze();
    
    dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
    {
       GeneratedImage = backgroundThreadImage;
    }));
    

    Clarification

    In the above code it is critical that Dispatcher.CurrentDispatcher be accessed from the UI thread, not from the generator thread. Every thread has its own Dispatcher. If you call Dispatcher.CurrentDispatcher from the generator thread you will get its Dispatcher instead of the one you want.

    In other words, you must do this:

      var dispatcher = Dispatcher.CurrentDispatcher;
    
      var generatorThreadStarter = new ThreadStart(() =>
         GenerateImages(coordinates, dispatcher));
    

    and not this:

      var generatorThreadStarter = new ThreadStart(() =>
         GenerateImages(coordinates, Dispatcher.CurrentDispatcher));
    

提交回复
热议问题