1

I have a simple method which call a function that returns a bitmap image.

private void ImageToGrayScale(object sender, RoutedEventArgs e)
{
    pbStatus.Visibility = Visibility.Visible;
    if (loadedImage != null)
    {
        new Thread(() =>
        {
             BitmapImage bitmapImage= ThreadProcedure();
             this.Dispatcher.Invoke(new Action(()=> {
                 pbStatus.Visibility = Visibility.Hidden;
                 EditedImage.Source = bitmapImage;
             }));
        }).Start();
    }
    else
    {
        MessageBox.Show("Please select the image first!");
    }
}

Everytime at line: EditedImage.Source = bitmapImage; a get an error:

The calling thread cannot access this object because a different thread owns it.

Also, here is the method which returns a bitmap image.

private BitmapImage ThreadProcedure()
{
     Bitmap editedImage = new Bitmap(loadedImage);
     for (int x = 0; x < editedImage.Width; x++)
     {
         for (int y = 0; y < editedImage.Height; y++)
         {
             Color pixelColor = editedImage.GetPixel(x, y);
             int rgb = (int)((pixelColor.R + pixelColor.G + pixelColor.B) / 3);
             editedImage.SetPixel(x, y, Color.FromArgb(rgb, rgb, rgb)); // Now greyscale
         }
     }
     return Converter.ConvertBitmapToBitmapImage(editedImage, extension);
 }
Mihai Alexandru-Ionut
  • 47,092
  • 13
  • 101
  • 128
  • What is loadedImage, is that the problem? You create new Bitmap from it in the thread process. Or maybe you should pass the bitmapImage as a parameter to the dispatcher delegate... – japesu Mar 03 '17 at 11:00
  • The issue here is most likely with the `bitmapImage` object - it's created on a different thread to the Dispatcher sync context. So reading from it, and copying it to the Source is probably failing with this error. To test this, move the call to `ThreadProcedure` inside the dispatcher invoke and see if it works. – Baldrick Mar 03 '17 at 11:02
  • @Baldrick, it works, but it blocks the UI thread and the window it is not responsive. – Mihai Alexandru-Ionut Mar 03 '17 at 11:07
  • So create delegate for the dispatcher process and pass the bitmapImage as a parameter when it has been created in you thread. – japesu Mar 03 '17 at 11:10
  • @japesu, i got same error. – Mihai Alexandru-Ionut Mar 03 '17 at 11:14
  • @Alexandru-IonutMihai, check the link in the answer below, is it possible that `EditedImage.Dispatcher` and `this.Dispatcher` are different? If so, you'll have to make another `Invoke`. Like `this.EditedImage.Dispatcher.Invoke(() => this.EditedImage.Source = blabla)` – Nerlog Mar 03 '17 at 11:30
  • @Nerlog, same error. – Mihai Alexandru-Ionut Mar 03 '17 at 15:03

4 Answers4

1

You should freeze the BitmapImage by calling its Freeze() method in order to be able to use it on another thread than the one on which it was created:

new Thread(() =>
{
        BitmapImage bitmapImage = ThreadProcedure();
        bitmapImage.Freeze(); //<--

        this.Dispatcher.Invoke(new Action(() => {
            pbStatus.Visibility = Visibility.Hidden;
            EditedImage.Source = bitmapImage;
        }));
}).Start();
mm8
  • 163,881
  • 10
  • 57
  • 88
0

There is a difference between Dispatcher and Application.Current.Dispatcher:

Dispatcher.CurrentDispatcher vs. Application.Current.Dispatcher

Community
  • 1
  • 1
Nawed Nabi Zada
  • 2,819
  • 5
  • 29
  • 40
0

Make sure the dispatcher you use is the same one for the EditedImage object. You could use the latter dispatcher directly (see https://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcherobject.dispatcher(v=vs.110).aspx )

Nerlog
  • 261
  • 1
  • 5
-1

Creating a thread for updating an image is not the best thing to do use Dispatcher.BeginInvoke instead this will execute the action asynchronous.

"Control.BeginInvoke: Executes on the UI thread, and calling thread doesn't wait for completion."

Remove the thread part and use this code the problem should be solved.

         BitmapImage bitmapImage= ThreadProcedure();

         Dispatcher.BeginInvoke(DispatcherPriority.Input, new Action(() =>
         {
             pbStatus.Visibility = Visibility.Hidden;
             EditedImage.Source = bitmapImage;
         }));