使用ListView

时间:2017-02-12 03:57:28

标签: c# winforms listview

我最近开始分析我的WinForms应用程序,并在向上和向下滚动ListView时注意到内存泄漏。

如果我不通过.OwnerDraw和DrawItem进行自己的自定义渲染,则不会发生此泄漏。

我的ListView包含一个图像,文本和一个绘制在所选对象之上的矩形。我错过了一些清理工作吗?它似乎无休止地重绘东西,这就是为什么内存使用堆积起来。

如果我不断在列表中上下滚动,它会在10秒内爬升到超过100mb的内存使用量。如果我不使用OwnerDraw,内存使用率将保持一致。

根据我见过的例子,我的用法似乎有效。

感谢您的帮助。

// ## Inside form load ## //
listView2.OwnerDraw = true;
listView2.DrawItem += new DrawListViewItemEventHandler(listView2_DrawItem);

// ## How the items are added to the ListView (in form load) ## //

// Create an image list
ImageList imageList = new ImageList();
imageList.ImageSize = new Size(256, 178);
imageList.ColorDepth = ColorDepth.Depth32Bit;
// Assign the image list to the listView
listView2.LargeImageList = imageList;
// Create an array of 20 listView items
ListViewItem[] items = new ListViewItem[20];

// Create 20 items
for (int i = 0; i < 20; i++)
{
    // Add the image for this item to the image list
    imageList.Images.Add(Image.FromFile("myFile2.jpg"));
    // Create the item
    items[i] = new ListViewItem("Item");
    items[i].ImageIndex = i;
    // Add the item to the listView
    listView2.Items.Add(icons[i]);
}

// ## Draw item handler ## //
private void listView2_DrawItem(object sender, DrawListViewItemEventArgs e)
{   
    Rectangle rect3 = new Rectangle(e.Bounds.Left + 10, e.Bounds.Top + 10, 256, 178);
    Rectangle rect4 = new Rectangle(rect3.Left, e.Bounds.Top, rect3.Width, e.Bounds.Height + 14);
    TextFormatFlags flags = TextFormatFlags.HorizontalCenter |
            TextFormatFlags.Bottom | TextFormatFlags.WordBreak;

    // Draw the image for this item
    e.Graphics.DrawImage(e.Item.ImageList.Images[e.ItemIndex], rect3);

    // Draw the text and the surrounding rectangle.
    TextRenderer.DrawText(e.Graphics, e.Item.Text, new Font("Arial", 12), rect4, Color.Black, flags);

    if (e.Item.Selected)
    {
        int width = e.Item.ImageList.Images[e.ItemIndex].Width;
        int height = e.Item.ImageList.Images[e.ItemIndex].Height;
        Brush brush = new SolidBrush(Color.FromArgb(180, 1, 1, 1));
        e.Graphics.FillRectangle(brush, rect3);

        TextFormatFlags flags2 = TextFormatFlags.HorizontalCenter |
            TextFormatFlags.VerticalCenter | TextFormatFlags.WordBreak;

        // Draw the text
        TextRenderer.DrawText(e.Graphics, e.Item.Text, new Font("Arial", 12), rect3, Color.White, flags2);
    }
}

2 个答案:

答案 0 :(得分:1)

您需要处置新的字体(&#34; Arial&#34;,12)对象和画笔。

你泄漏的不仅仅是内存,你也在泄漏GDI对象。

您可以在表单加载时创建一次字体,并在表单关闭时处理它(更好的性能),或者使用需要它的DrawItem块中的using块创建和处理它(更慢,但更简单的代码)< / p>

答案 1 :(得分:0)

解决方案是使用:

this.listView2.LargeImageList.Draw(e.Graphics, gameItemRect.Left, gameItemRect.Top, gameItemRect.Width, gameItemRect.Height, e.ItemIndex);

这使用内部句柄而不是创建图像的副本。 此外,刷子和字体需要在代码块之外进行预初始化,以防止为每个绘制事件和泄漏内存重新创建它们,如@Tim所述。主内存泄漏是由于图像绘制调用。

现在内存使用情况与不使用OwnerDraw的情况一致。