在 WPF 中显示字节数组中的图像 - 内存问题
我开发了一个应用程序来捕获图像并将其保存到数据库,但我遇到了内存使用问题。在我的域对象上,我有 3 个属性:
Image - 字节数组,内容是 jpg
RealImageThumb - 字节数组转换为 BitmapImage 并缩小,在网格视图中与其他缩略图一起显示给用户
RealImage - 没有设置器,转换后的字节数组对于位图源,当用户将鼠标悬停在其上时,它会显示在工具提示中。
我遇到的问题是,如果用户依次将鼠标悬停在每个图像上,内存使用量就会呈螺旋式上升。我意识到当用户将鼠标悬停在生成的位图源上并且内存没有释放时,我尝试为 RealImage 提供一个后备属性并将其分配为 null 之后,但内存再次没有被释放(等待垃圾集电极?)。
编辑:
这就是你的意思雷吗?我没有在工具提示中显示任何内容,如下所示,但如果我尝试定义 WeakReference
,我会收到 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;
}
}
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:
Image - Byte array, contents are a jpg
RealImageThumb - The byte array converted to a BitmapImage and shrunk, displayed to the user in a gridview with other thumbnails
RealImage - Has no setter, the byte array converted to a bitmap source, this is shown in a tooltip when the user hovers over it.
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?).
edit:
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;
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您需要做三件事:
构建 BitmapImage 时,使用 StreamSource 提供数据。不要使用 UriSource 或将 Uri 传递到构造函数中,这会导致图像被添加到图像缓存中。
在域对象的 RealImage 实现中,存储对 BitmapImage 的 WeakReference,而不是 BitmapImage 本身。获取 RealImage 时,如果 WeakReference 或 WeakReference.Target 为 null,则创建一个新的 BitmapImage 和一个指向它的新 WeakReference。
使用带有模板切换的 DataTrigger,仅在可见时将 Image 控件包含在可视化树中
使用带有
以下是第 3 步所需的模板,包括带有 DataTrigger 的模板:
现在您可以像这样定义 ToolTip:
工作原理: 两个 ContentPresenter 相互嵌套:
您需要这样做的原因是,工具提示可能会尝试通过在弹出窗口显示后不将其丢弃来优化性能。
更新
您为 RealImage 发布的代码应该可以工作,并且几乎正是我的想法。今天早上我意识到,只要没有指定 SourceUri,实际上就不需要设置 BitmapCacheOption 或 BitmapCreateOption。我更新了我的答案以反映这一点并澄清 WeakReference 的事情。我还纠正了模板中的一个错误:当我应该绑定到“RealImage.Target”时,我却绑定到“RealImage”。
You will need to do three things:
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.
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.
Use a DataTrigger with template switching to only include your Image control in the visual tree when it is visible
Here are the templates needed for step 3, including the one with the DataTrigger:
Now you can define your ToolTip like this:
How it works: There are two ContentPresenters inside one another:
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.
Update
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".