如何将System.Drawing.Icon转换为Microsoft.UI.Xaml.ImageSource?
WinUI中System.Drawing.Icon转Microsoft.UI.Xaml.ImageSource的解决方案
方法一:通过MemoryStream转换(简单易实现)
将Icon转换为GDI+ Bitmap后保存到内存流,再用WinUI的BitmapImage加载,适合大多数场景:
using System.Drawing; using System.IO; using Microsoft.UI.Xaml.Media.Imaging; using Windows.Storage.Streams; public static ImageSource IconToImageSource(Icon icon) { if (icon == null) return null; using var stream = new MemoryStream(); icon.ToBitmap().Save(stream, System.Drawing.Imaging.ImageFormat.Png); stream.Position = 0; var bitmapImage = new BitmapImage(); bitmapImage.SetSource(stream.AsRandomAccessStream()); return bitmapImage; }
注意事项
- 需确保在UI线程调用此方法,因为BitmapImage的
SetSource操作依赖UI线程上下文;若在非UI线程,可通过DispatcherQueue切换:await DispatcherQueue.TryEnqueue(async () => { MyImage.Source = IconToImageSource(myIcon); }); - 使用PNG格式保存可保留图标透明度,避免背景变黑。
方法二:通过Win32 API+WinRT SoftwareBitmap转换(高效低开销)
直接基于Icon的HBITMAP创建WinRT SoftwareBitmap,跳过GDI+的Bitmap转换,性能更优:
using System.Drawing; using System.Runtime.InteropServices; using Microsoft.UI.Xaml.Media.Imaging; using Windows.Graphics.Imaging; using Windows.Storage.Streams; [DllImport("gdi32.dll", SetLastError = true)] private static extern bool DeleteObject(IntPtr hObject); public static async Task<ImageSource> IconToImageSourceAsync(Icon icon) { if (icon == null) return null; IntPtr hBitmap = icon.ToBitmap().Handle; try { using var decoder = await GdiBitmapDecoder.CreateAsync(hBitmap); var softwareBitmap = await decoder.GetSoftwareBitmapAsync(); var bitmapSource = new BitmapSource(); await bitmapSource.SetSourceAsync(softwareBitmap.AsRandomAccessStream()); return bitmapSource; } finally { // 必须释放GDI资源,防止内存泄漏 DeleteObject(hBitmap); } }
注意事项
- 必须调用
DeleteObject释放HBITMAP,否则会导致GDI资源泄漏; - 异步方法需注意线程调度,同样需在UI线程更新Image控件的Source属性。
为什么BitmapSource.FromAbi会报错?
BitmapSource.FromAbi的参数要求是WinRT BitmapSource对象的ABI指针,而System.Drawing.Icon.Handle是HICON(图标句柄),两者类型完全不匹配,直接传入会触发内存访问违例,因此不能用该方法转换。
内容的提问来源于stack exchange,提问作者Jack251970
相关产品推荐
相关产品推荐

