Reputation: 49
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
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
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