【问题标题】:WPF image stop repaintingWPF图像停止重绘
【发布时间】:2015-06-09 16:04:27
【问题描述】:

我正在尝试使用 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();
        }
  }

最终绑定到我的视图:

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

在我的Image上直接绑定TestImage
View

<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");我也有同样的例外

请注意,Edit2 和 Edit3 是一个测试,不回答我原来的问题

抱歉,帖子太长了

【问题讨论】:

  • Bitmap 的完整类型名称是什么?您是否尝试在视图模型中执行转换,并从 VM 公开 ImageSource 属性而不是 Bitmap?
  • 完整类型为System.Drawing.Bitmap。我试试看
  • 这正在慢慢变成一个调试会话。 Stack Overflow 上的帖子应该包含一个问题(不帮助我调试),并且随着时间的推移不会发生太大变化。也许您可以通过聊天获得帮助:chat.stackoverflow.com 并在解决问题后解决问题。

标签: c# wpf mvvm graphics


【解决方案1】:

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

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

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

【讨论】:

  • 好主意,但在我的视图模型中,我没有 ui 所以没有windowOrControl
  • 但是您使用的是 WPF - 而且您有一个窗口,对吗?您已经创建了一个图像和一些其他 UI 元素 - 所以有一个 UI 线程正在运行。你甚至可以试试 Application.Current.Dispatcher ...
  • 是我做的 :) 检查我的“编辑 3”
  • 您只需要使用最初在窗口上创建图像控件的同一个调度程序,每个 UI 元素都有调度程序属性...找到这不是最难的部分 :-)主窗口?如果是的话,把dispatcher的引用传给ViewModel,或者静态引用,有很多方法可以解决这个...
【解决方案2】:

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

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

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

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

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

【讨论】:

    【解决方案3】:

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

    [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;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-09-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多