1

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

图片 - 字节数组,内容为 jpg

RealImageThumb - 转换为 BitmapImage 并缩小的字节数组,在网格视图中与其他缩略图一起显示给用户

RealImage - 没有设置器,将字节数组转换为位图源,当用户将鼠标悬停在它上面时,它会显示在工具提示中。

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

编辑:

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

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

1 回答 1

3

你需要做三件事:

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

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

  3. 使用带有模板切换的 DataTrigger 以仅在可视化树中包含您的 Image 控件(当它可见时)

以下是第 3 步所需的模板,包括带有 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>

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

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

它是如何工作的:彼此内部有两个 ContentPresenter:

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

您需要这样做的原因是,工具提示可能会尝试通过在显示弹出窗口后不处理来优化性能。

更新

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

于 2010-06-16T02:01:18.853 回答