Using WPF and MVVM I'm trying to display camera images into a Image
.
Each frame camera got, a callback is called :
Viewmodel
public void OnNewFrame(object sender, EventArgs e)
{
Camera camera = sender as MyCamera;
camera.ToBitmap(out _bmpImage);
RaisePropertyChanged("BMPImage");
}
Each frame, I update the variable _bmpImage :
ViewModel
private Bitmap _bmpImage;
public Bitmap BMPImage
{
get
{ return _bmpImage; }
private set
{ _bmpImage = value; RaisePropertyChanged("BMPImage"); }
}
In order to convert the Bitmap
to BitmapImage
I use a converter :
Converter
public class ImageToSource : IValueConverter
{
public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
Image image = value as Image;
if (image != null)
{
MemoryStream ms = new MemoryStream();
image.Save(ms, ImageFormat.Bmp);
ms.Seek(0, SeekOrigin.Begin);
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.StreamSource = ms;
bi.EndInit();
return bi;
}
return null;
}
public object ConvertBack(object value, Type targetType,
object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
Finnaly bind to my view :
<Image Source="{Binding Main.BMPImage, Converter={StaticResource ImageToSource}}"></Image>
It's work good the 15 first second, but after this delay : my Image
becomes white. In the Converter, image
is never null
so camera works well. The problem is the component Image
stop repainting.
When the Image
is white, I can resize the window or move it and the image becomes good because Image
is repainting.
There is something I do wrong ?
There are a way to force Image
repainting ?
Why Image
stop repainting ?
Thanks
EDIT1:
After some verification, when image becomes white, all ui freeze (so my button are not clickable until I resize or move the window)
EDIT2
as Dennis in the comment suggered me, I tryed to do the conversion in my ViewModel :
For that, I add a property which represent the converted image :
private BitmapImage _testImage;
public BitmapImage TestImage
{
get
{ return _testImage; }
private set
{ _testImage = value; RaisePropertyChanged("TestImage"); }
}
And I converted _bmpImage
directly into OnNewFrame
:
public void OnNewFrame(object sender, EventArgs e)
{
Camera camera = sender as MyCamera;
camera.ToBitmap(out _bmpImage);
//RaisePropertyChanged("BMPImage");
if (_bmpImage != null)
{
// Convertion
MemoryStream ms = new MemoryStream();
_bmpImage.Save(ms, ImageFormat.Bmp);
ms.Seek(0, SeekOrigin.Begin);
_testImage = new BitmapImage();
_testImage.BeginInit();
_testImage.StreamSource = ms;
_testImage.EndInit();
RaisePropertyChanged("TestImage");
}
}
and bind directly the TestImage
on my Image
View
<Image Source="{Binding Main.TestImage}" />
And with this code I've the exception :
Must create DependencySource on same Thread as the DependencyObject
EDIT 3
I have considered your remarks and it's my new code :
if (_bmpImage != null)
{
// Convertion
Console.WriteLine("ok");
MemoryStream ms = new MemoryStream();
_bmpImage.Save(ms, ImageFormat.Bmp);
ms.Seek(0, SeekOrigin.Begin);
_testImage = new BitmapImage();
_testImage.BeginInit();
_testImage.StreamSource = ms;
_testImage.EndInit();
ms.Dispose();
System.Windows.Application.Current.Dispatcher.BeginInvoke((Action)(() =>
{
RaisePropertyChanged("TestImage");
}));
}
I've the same exception on RaisePropertyChanged("TestImage");
Juste note that Edit2 and Edit3 are a test and doesn't answer to the my original question
Sorry for the long post
I'll bet Your OnNewFrame method does not run on the UI thread.
In your code, change this line so it runs on the UI thread buy calling Invoke or BeginInvoke on the Dispatcher property of your window / control:
windowOrControlDispatcher.BeginInvoke((Action) (() =>
{
RaisePropertyChanged("TestImage");
}));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With