【问题标题】:WPF In-Memory Image DisplayWPF 内存图像显示
【发布时间】:2010-06-10 19:59:44
【问题描述】:
我正在尝试为我的列表视图构建一个项目模板,并且我绑定到一个实体列表。我拥有的实体有一个我想显示的System.Drawing.Image,但到目前为止,我无法弄清楚如何将它绑定到<Image> 块。
我可以在互联网上找到的每个示例和文档都与可通过uri 访问的图像有关,即硬盘上或网站上的文件
<DataTemplate x:Key="LogoPreviewItem">
<Border BorderBrush="Black" BorderThickness="1">
<DockPanel Width="150" Height="100">
<Image>
<Image.Source>
<!--
{Binding PreviewImage} is where the System.Drawing.Image
is in this context
-->
</Image.Source>
</Image>
<Label DockPanel.Dock="Bottom" Content="{Binding CustomerName}" />
</DockPanel>
</Border>
</DataTemplate>
【问题讨论】:
标签:
.net
wpf
image
data-binding
【解决方案1】:
System.Drawing.Image 是一个 WinForms / GDI+ 对象,在 WPF 世界中确实不合适。纯 WPF 程序通常不会使用 System.Drawing.Image,而是使用 BitmapSource。然而,有时我们会被旧东西卡住一段时间。
您可以将图像从旧技术转换为新技术,如下所示:
var oldImage = ...; // System.Drawing.Image
var oldBitmap =
oldImage as System.Drawing.Bitmap ??
new System.Drawing.Bitmap(oldImage);
var bitmapSource =
System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
oldBitmap.GetHbitmap(System.Drawing.Color.Transparent),
IntPtr.Zero,
new Int32Rect(0, 0, oldBitmap.Width, oldBitmap.Height),
null);
现在你可以设置:
myImage.Source = bitmapSource;
这比其他地方描述的 MemoryStream 方法快得多,因为它从不将位图数据序列化为流。
【解决方案2】:
Ray Burns 的回答导致内存泄漏,因为
oldBitmap.GetHbitmap(System.Drawing.Color.Transparent)
分配永远不会释放的内存。
如GetHbitmap (Microsoft Docs) 文档中的“备注”中所述:
您负责调用 GDI DeleteObject 方法来释放 GDI 位图对象使用的内存。
按照文档,通过导入和使用DeleteObject()释放内存:
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);
var hBitmap = someBitmap.GetHbitmap(...);
// Do something with hBitmap
DeleteObject(hBitmap);
因此,Ray Burns 的答案应修改为:
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);
...
var oldImage = ...; // System.Drawing.Image
var oldBitmap =
oldImage as System.Drawing.Bitmap ??
new System.Drawing.Bitmap(oldImage);
var hOldBitmap = oldBitmap.GetHbitmap(System.Drawing.Color.Transparent);
var bitmapSource =
System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
hOldBitmap,
IntPtr.Zero,
new Int32Rect(0, 0, oldBitmap.Width, oldBitmap.Height),
null);
DeleteObject(hOldBitmap);