从 SQL 数据库添加图像时,ImageList 抛出 "Out of memory" 异常

ImageList throws "Out of memory" exception when adding images from SQL database

我有几个 SQL 数据库,其中 table 使用 varbinary 数据类型存储图像。

单击按钮时,它将从 ImageList 控件中删除除前三个图像之外的所有现有图像,并将所有新图像添加到我的表单上的 ImageList

有一个 TreeView 使用这个 ImageList

我得到了:

Out of memory exception

...如果我在相同 数据库上单击按钮多次

简化代码:

if(imageList1.Images.Count > 3)
{
    for (int i = imageList1.Images.Count - 1; i > 2; i--)
    {
       imageList1.Images.RemoveAt(i);      
    }
}
int counter = 0;
foreach (DataRow dr in dataset.Tables[0].Rows)
{
    if (dr["ImageField"] != DBNull.Value)
    {
        byte[] imageData = (byte[])dr["ImageField"];
        MemoryStream ms = new MemoryStream(imageData, 0, imageData.Length);
        Bitmap img = new Bitmap(ms);
        imageList1.Images.Add("Image" + counter, img);
        img.Dispose();
        ms.Dispose();
        counter++;
    }
}

堆栈跟踪:

at System.Drawing.Graphics.FromHdcInternal(IntPtr hdc)
   at System.Drawing.Font.ToLogFont(Object logFont)
   at System.Drawing.Font.ToHfont()
   at System.Windows.Forms.Control.FontHandleWrapper..ctor(Font font)
   at System.Windows.Forms.OwnerDrawPropertyBag.get_FontHandle()
   at System.Windows.Forms.TreeView.CustomDraw(Message& m)
   at System.Windows.Forms.TreeView.WmNotify(Message& m)
   at System.Windows.Forms.TreeView.WndProc(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
   at System.Windows.Forms.UnsafeNativeMethods.SendMessage(HandleRef hWnd, Int32 msg, IntPtr wParam, IntPtr lParam)
   at System.Windows.Forms.Control.SendMessage(Int32 msg, IntPtr wparam, IntPtr lparam)
   at System.Windows.Forms.Control.ReflectMessageInternal(IntPtr hWnd, Message& m)
   at System.Windows.Forms.Control.WmNotify(Message& m)
   at System.Windows.Forms.Control.WndProc(Message& m)
   at System.Windows.Forms.ScrollableControl.WndProc(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
   at System.Windows.Forms.UnsafeNativeMethods.CallWindowProc(IntPtr wndProc, IntPtr hWnd, Int32 msg, IntPtr wParam, IntPtr lParam)
   at System.Windows.Forms.NativeWindow.DefWndProc(Message& m)
   at System.Windows.Forms.Control.DefWndProc(Message& m)
   at System.Windows.Forms.Control.WndProc(Message& m)
   at System.Windows.Forms.TreeView.WndProc(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
   at System.Windows.Forms.UnsafeNativeMethods.SendMessage(HandleRef hWnd, Int32 msg, Int32 wParam, Int32 lParam)
   at System.Windows.Forms.Control.EndUpdateInternal(Boolean invalidate)
   at System.Windows.Forms.TreeView.ImageListChangedHandle(Object sender, EventArgs e)
   at System.EventHandler.Invoke(Object sender, EventArgs e)
   at System.Windows.Forms.ImageList.OnChangeHandle(EventArgs eventargs)
   at System.Windows.Forms.ImageList.ImageCollection.Add(Original original, ImageInfo imageInfo)
   at System.Windows.Forms.ImageList.ImageCollection.Add(String key, Image image)
   at Test.MyClass.LoadLibraryImageList()

为什么在内存占用很低的时候会抛出那个异常?

删除图像时必须处理它们(有关说明,请参阅 this article)。

此外,while 循环更简单。只需删除列表中的最后一张图片,直到只剩下 3 张。

void RemoveLastImage(ImageList imageList)
{
    var lastIndex = imageList.Images.Count - 1;
    var lastImage = imageList.Images[lastIndex];
    imageList.Images.RemoveAt(lastIndex);
    lastImage.Dispose();
}

while (imageList1.Images.Count > 3)
{
    RemoveLastImage(imageList1);
}

看起来ImageList只是冰山一角,真正的问题在于我扩展的MultiSelectTreeView控件。阅读此 question 后,每当我更改 TreeNode 字体时,我都会将 GC.Collect() 添加到我的代码中,瞧,问题解决了。

根据建议,我还在加载新批次之前处理了 ImageList 中不需要的图像,这似乎也有助于降低我的 GDI 计数。谢谢大家。