Replace the parameterized Action<BitmapImage> with a parameterless Action that captures converted, and freeze the background-created image before dispatching it to the UI thread.
// Runs on the background thread.
BitmapImage converted = Convert(BitmapConverter.ToBitmap(matImage));
if (converted.CanFreeze)
converted.Freeze();
imgViewport.Dispatcher.BeginInvoke(
DispatcherPriority.Normal,
new Action(() =>
{
imgViewport.Source = converted;
}));
Why the exception occurs
Your delegate declares one required parameter:
new Action<BitmapImage>((converted) => { ... })
However, the selected BeginInvoke(DispatcherPriority, Delegate) overload supplies no arguments to that delegate. Consequently, invocation expects one parameter but receives zero, producing TargetParameterCountException. That exception specifically indicates that the invocation's supplied parameter count differs from the delegate's expected count.^1^
The captured-variable version uses an Action with zero parameters, matching that overload. BeginInvoke then queues the UI update asynchronously on the dispatcher's thread.^2^
Using imgViewport.Dispatcher also ensures that the dispatcher belongs to the UI element being updated.
Alternative: pass the bitmap as an explicit argument
If a parameterized delegate is preferable, use the overload that accepts an argument:
if (converted.CanFreeze)
converted.Freeze();
imgViewport.Dispatcher.BeginInvoke(
DispatcherPriority.Normal,
new Action<BitmapImage>(bitmap =>
{
imgViewport.Source = bitmap;
}),
converted);
Here, converted is explicitly supplied as the argument for the delegate's bitmap parameter. Do not name the lambda parameter converted when an outer variable has the same name; although legal in some contexts, it obscures which value is being used.
Cross-thread image ownership
Fixing the parameter count does not by itself make an image created on a worker thread transferable. WPF UI objects have thread affinity, and BitmapImage participates in WPF's Freezable model. An unfrozen Freezable cannot be shared across threads; a frozen one can.^3^
Therefore:
- Complete the conversion and all image modifications on the worker thread.
- Check
CanFreeze and call Freeze() there.
- Dispatch only the short
imgViewport.Source assignment.
- Do not modify the image after freezing it.
If CanFreeze is false, create or copy the WPF image on the UI thread instead, while leaving the expensive OpenCV processing on the worker thread. The Image.Source property accepts an ImageSource, including a BitmapImage.^4^
References
- TargetParameterCountException Class-Definition
- Dispatcher.BeginInvoke Method-Definition
- Freezable Objects Overview
- Defines the Source property of the Image control, which gets or sets the ImageSource for the image.