luisNET
luisNET

Reputation: 49

WPF error with thread

I have an MVVM application that processes images. The problem is that running thread generates an error.

public void  VINIRExecute()
    {
        var value = Task.Run(() => this.viService.getVI(bitmapNIR));
    }

 public BitmapImage getVI(BitmapImage imageNIR)
    {
        int height = imageNIR.PixelHeight;
        int width = imageNIR.PixelWidth;
        int nStride = (imageNIR.PixelWidth * imageNIR.Format.BitsPerPixel + 7) / 8;
        byte[] pixelByteArray = new byte[imageNIR.PixelHeight * nStride];
        imageNIR.CopyPixels(pixelByteArray, nStride, 0);

        WriteableBitmap wb = new WriteableBitmap(imageNIR);

        int aux = 0;
        Int32Rect rect;
        double vi;

        for (int i = 0; i < height; i++)
        {

            for (int j = 0; j < width; j++)
            {
                var red = (double)pixelByteArray[aux + 1] == 0 ? 1 : (double)pixelByteArray[aux + 1];
                vi = (double)pixelByteArray[aux + 2] / (double)red;
                rect = new Int32Rect(j, i, 1, 1);
                wb.WritePixels(rect, getColor(vi), 4, 0);
                aux += 4;
            }
            aux = nStride * i;
        }
        pixelByteArray = null;
        return BitmapTransform.BitmapProcess.ConvertWriteableBitmapToBitmapImage(wb);
    }

In the first line of the function getVI appear error:

System.InvalidOperationException was unhandled by user code HResult=-2146233079 Message=El subproceso que realiza la llamada no puede obtener acceso a este objeto porque el propietario es otro subproceso. Source=WindowsBase StackTrace: en System.Windows.Threading.DispatcherObject.VerifyAccess() en System.Windows.Media.Imaging.BitmapSource.get_PixelHeight() en ImageProcessor.Services.VI.getVI(BitmapImage imageNIR) en c:\Users\Luis\Documents\Visual Studio 2013\Projects\ImageProcessor\ImageProcessor\Services\VI.cs:línea 48 en ImageProcessor.ViewModels.VMProcessWindow.b__a() en c:\Users\Luis\Documents\Visual Studio 2013\Projects\ImageProcessor\ImageProcessor\ViewModels\VMProcessWindow.cs:línea 189 en System.Threading.Tasks.Task`1.InnerInvoke() en System.Threading.Tasks.Task.Execute() InnerException:

I have tried several ways, but always the same error. thanks

Upvotes: 1

Views: 1827

Answers (2)

Clemens
Clemens

Reputation: 128061

You could improve the getVI method like this:

public BitmapSource getVI(BitmapSource bitmapNIR)
{
    if (bitmapNIR.Format.BitsPerPixel != 32)
    {
        // method only works with 4 bytes per pixel
        throw new InvalidOperationException("BitmapSource must have 32 bits per pixel");
    }

    var height = bitmapNIR.PixelHeight;
    var width = bitmapNIR.PixelWidth;
    var stride = 4 * width;
    var pixels = new byte[height * stride];

    bitmapNIR.CopyPixels(pixels, stride, 0);

    for (int i = 0; i < pixels.Length; )
    {
        var red = (double)Math.Min((byte)1, pixels[i + 1]);
        var vi = (double)pixels[i + 2] / red;
        var color = getColor(vi);
        pixels[i++] = color[0];
        pixels[i++] = color[1];
        pixels[i++] = color[2];
        pixels[i++] = color[3];
    }

    var bitmapVI = BitmapSource.Create(
        width, height, 96d, 96d, bitmapNIR.Format, null, pixels, stride);

    bitmapVI.Freeze();
    return bitmapVI;
}

It is probably no longer necessary to run it in a Task:

public void  VINIRExecute()
{
    var bitmapVI = viService.getVI(bitmapNIR);
}

If you still need to do that, you'll have to freeze bitmapNIR before running the Task:

public void  VINIRExecute()
{
    bitmapNIR.Freeze();
    var task = Task.Run(() => viService.getVI(bitmapNIR));        
}

Upvotes: 1

Michal Ciechan
Michal Ciechan

Reputation: 13888

The problem is you are accessing a UI element from another thread than its owner. WPF is STA (Single-threaded-affinity).

Have a look at: How to access c# WPF control in thread safe way?

Upvotes: 1

Related Questions