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

Image - 字节数组,内容为jpg

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

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

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

编辑:

雷,这就是你的意思吗?我没有在工具提示中显示任何内容,如下所示,但是如果我尝试定义一个 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;
            }
        }
有帮助吗?

解决方案

您需要做三件事:

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

  2. 在域对象的 RealImage 实现中,存储对 BitmapImage 的 WeakReference,而不是 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”。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top