从WPF中的字节数组显示图像 - 内存问题 [英] Display Image from Byte Array in WPF - Memory Issues

查看:287
本文介绍了从WPF中的字节数组显示图像 - 内存问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我开发了一个应用程序来捕获图像并将其保存到数据库,但我遇到了内存使用问题。在我的域对象上,我有3个属性:

I've developed an application to capture and save images to a database, but I'm having an issue with memory usage. On my domain object I have 3 properties:

图像 - 字节数组,内容是jpg

Image - Byte array, contents are a jpg

RealImageThumb - 字节数组转换为BitmapImage并缩小,在gridview中以其他缩略图显示给用户

RealImageThumb - The byte array converted to a BitmapImage and shrunk, displayed to the user in a gridview with other thumbnails

RealImage - 没有setter,字节数组转换为位图源,当用户将鼠标悬停在工具提示上时,会显示此信息。

RealImage - Has no setter, the byte array converted to a bitmap source, this is shown in a tooltip when the user hovers over it.

我遇到的问题是,如果用户依次悬停在每个图像上,则内存使用量会呈螺旋式上升。我意识到当用户盘旋位图源生成并且内存没有被释放时,我已经尝试给RealImage一个后备属性并将其分配给null但是内存没有被释放(等待垃圾)收藏家?)。

The issue I have is that if a user hovers over each image in turn the memory usage spirals. I realise that as a user hovers over bitmap sources are generated and the memory isn't freed up, I've tried giving RealImage a backing property and assigning this to null after but again the memory isn't freed up (waiting for the garbage collector?).

编辑:

这是你的意思雷吗?我没有在工具提示中显示任何内容,如下所示,但如果我尝试定义 WeakReference< BitmapImage> ,我会得到System.WeakReference没有类型参数错误。

Is this what you meant Ray? I'm not getting anything shown in the tooltip as below, but if I try and define a WeakReference<BitmapImage>, I get the System.WeakReference does not have type parameters error.

  private WeakReference _realImage;
        public virtual BitmapImage RealImage
        {
            get
            {
                if (_realImage == null || _realImage.Target == null)
                {

                    if (Image == null) return null;
                    var newBitmapImage = new BitmapImage();
                    newBitmapImage.BeginInit();
                    newBitmapImage.CacheOption = BitmapCacheOption.None;
                    newBitmapImage.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
                    newBitmapImage.StreamSource = new MemoryStream(Image);
                    newBitmapImage.EndInit();
                    _realImage = new WeakReference(newBitmapImage);
                }

                return (BitmapImage)_realImage.Target;
            }
        }


推荐答案

你将需要做三件事:


  1. 构建BitmapImage时,使用StreamSource提供数据。不要使用UriSource或将Uri传递给构造函数,这会导致图像被添加到图像缓存中。

  1. When constructing your BitmapImage use StreamSource to supply the data. Do not use UriSource or pass a Uri into the constructor, which would cause the image to be added to the image cache.

在域对象的RealImage实现中,将WeakReference存储到BitmapImage而不是BitmapImage本身。当获取RealImage时,如果WeakReference或WeakReference.Target为null,则创建一个新的BitmapImage和一个新的WeakReference。

In your domain object's RealImage implementation, store a WeakReference to your BitmapImage not the BitmapImage itself. When RealImage is fetched, if either WeakReference or WeakReference.Target is null, create a new BitmapImage and a new WeakReference to it.

使用带有模板切换的DataTrigger仅在可视树中显示图像控件时

Use a DataTrigger with template switching to only include your Image control in the visual tree when it is visible

以下是步骤3所需的模板,包括带有DataTrigger的那个:

Here are the templates needed for step 3, including the one with the DataTrigger:

<DataTemplate x:Key="EmptyTemplate">
</DataTemplate>

<DataTemplate x:Key="RealImageTemplate">
  <Image Source="{Binding RealImage.Target}" Width="300" Height="300" />
</DataTemplate>

<DataTemplate x:Key="RealImageWhenVisible">

  <!-- Use EmptyTemplate when I am not visible -->
  <ContentPresenter x:Name="Presenter"
                    Content="{Binding}"
                    ContentTemplate="{StaticResource EmptyTemplate}"/>

  <!-- Switch to RealImageTemplate when I am visible -->
  <DataTemplate.Triggers>
    <DataTrigger Binding="{Binding IsVisible, RelativeSource={RelativeSource Self}}"
                 Value="True">
      <Setter TargetName="Presenter"
              Property="ContentPresenter.ContentTemplate"
              Value="{StaticResource RealImageTemplate}" />
    </DataTrigger>
  </DataTemplate.Triggers>
</DataTemplate>

现在您可以像这样定义工具提示:

Now you can define your ToolTip like this:

<Rectangle Width="40" Height="40" Fill="Blue">
  <Rectangle.ToolTip>
    <ContentPresenter Content="{Binding}"
                      ContentTemplate="{StaticResource RealImageWhenVisible}" />
  </Rectangle.ToolTip>
</Rectangle>

工作原理:彼此内部有两个ContentPresenters:

How it works: There are two ContentPresenters inside one another:


  • 当外部ContentPresenter不可见时,内部ContentPresenter将具有EmptyTemplate,因此不会加载任何图像。

  • 当外部ContentPresenter可见时,内部ContentPresenter将具有RealImageTemplate,因此将加载并显示图像。

您需要执行此操作的原因是工具提示可能会尝试通过不显示弹出窗口来优化性能。

The reason you need to do this is that a ToolTip may attempt to optimize performance by not disposing of the Popup once it has been shown.

更新

您为RealImage发布的代码应该可以工作,几乎就是我想到的。我意识到今天早上只要没有指定SourceUri就没有必要设置BitmapCacheOption或BitmapCreateOption。我已经更新了我的答案以反映这一点,并澄清了WeakReference的事情。我还纠正了模板中的一个错误:当我应该绑定到RealImage.Target时,我绑定到RealImage。

The code you posted for RealImage ought to work, and is almost exactly what I was thinking of. I realized this morning there is really no need to set BitmapCacheOption or BitmapCreateOption as long as no SourceUri is specified. I've updated my answer to reflect this and also to clarify the WeakReference thing. I also corrected a bug in the template: I was binding to "RealImage" when I should have been binding to "RealImage.Target".

这篇关于从WPF中的字节数组显示图像 - 内存问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆