WPF图像停止重新绘制

时间:2015-06-05 09:29:58

标签: c# wpf mvvm graphics

使用WPF和MVVM我尝试将相机图像显示为Image。 每个帧摄像机都有一个回调叫做:

视图模型

public void OnNewFrame(object sender, EventArgs e)
{
    Camera camera = sender as MyCamera;
    camera.ToBitmap(out _bmpImage);
    RaisePropertyChanged("BMPImage");
}

每一帧,我更新变量_bmpImage:

视图模型

private Bitmap _bmpImage;
public Bitmap BMPImage
{
    get
    { return _bmpImage; }
    private set
    { _bmpImage = value; RaisePropertyChanged("BMPImage"); }
}

为了将Bitmap转换为BitmapImage我使用转换器:

转换器

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绑定到我的观点:

 <Image Source="{Binding Main.BMPImage, Converter={StaticResource ImageToSource}}"></Image>

在第一秒的第15秒,它的工作很好,但是在这个延迟之后:我的Image变成了白色。在转换器中,image永远不会null,因此相机效果很好。问题是组件Image停止重新绘制 当Image为白色时,我可以调整窗口大小或移动窗口,因为Image正在重新绘制,图像会变好。

我做错了什么?
有一种方法可以强制Image重画吗? 为什么Image停止重新粉饰?

由于

EDIT1:

经过一些验证后,当图像变白时,所有ui都会冻结(所以我的按钮不可点击,直到我调整大小或移动窗口)

EDIT2

由于丹尼斯在评论中提示我,我试图在我的ViewModel中进行转换:

为此,我添加了一个表示转换后图像的属性:

 private BitmapImage _testImage;
 public BitmapImage TestImage
 {
      get
      { return _testImage; }
      private set
      { _testImage = value; RaisePropertyChanged("TestImage"); }
 }

我将_bmpImage直接转换为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");
        }
    }

并直接绑定TestImage上的Image 查看

<Image Source="{Binding Main.TestImage}" />

使用此代码,我有例外:

Must create DependencySource on same Thread as the DependencyObject

编辑3

我考虑过你的评论,这是我的新代码:

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");
                }));

            }

我在RaisePropertyChanged("TestImage");

上遇到了同样的例外

Juste注意到Edit2和Edit3是一个测试,并没有回答我原来的问题

对不起,很长的帖子

3 个答案:

答案 0 :(得分:2)

我敢打赌你的OnNewFrame方法不会在UI线程上运行。

在你的代码中,更改此行,使其在UI线程上运行,在窗口/控件的Dispatcher属性上调用Invoke或BeginInvoke:

windowOrControlDispatcher.BeginInvoke((Action) (() =>
{
    RaisePropertyChanged("TestImage");
}));

答案 1 :(得分:0)

检查应用程序的内存消耗。

如果位图占用大量内存且应用程序没有处理图像和缓冲区

camera.ToBitmap(out _bmpImage);
// does this clean up the old _bmpImage?

MemoryStream ms = new MemoryStream();
// no dispose!

应用程序可能会花时间收集垃圾而不是更新UI。

答案 2 :(得分:0)

我终于找到了解决方案。我使用另一种方法来转换我的Bitmap(可能更快)

[System.Runtime.InteropServices.DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);

public object Convert(object value, Type targetType, object parameter,
        System.Globalization.CultureInfo culture)
{
    Bitmap bmp = value as Bitmap;

    if (bmp != null)
    {
        IntPtr hBitmap = bmp.GetHbitmap(); 
        var drawable = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
              hBitmap,
              IntPtr.Zero,
              Int32Rect.Empty,
              BitmapSizeOptions.FromEmptyOptions());

        DeleteObject(hBitmap);
        bmp.Dispose();
        return drawable;
    }
    return null;
}