如何根据需要在listview中加载缩略图?

时间:2014-10-23 20:37:49

标签: c# winforms listview imagelist

所以我希望能够根据图像文件路径列表填充1000个缩略图。我尝试使用下面的代码,但我意识到在200+图像之后,我的程序会给我一个"类型' System.OutOfMemoryException'的第一次机会异常。发生在System.Drawing.dll"。

private void PopulateThumbnails(List<string> queryResults)
{
    this.playerListView.Items.Clear();
    this.imageList1.Images.Clear();
    ImageViewer imageViewer = new ImageViewer();

    foreach (string file in queryResults)
    {
        try
            this.imageList1.Images.Add(Image.FromFile(file));
        catch
            Console.WriteLine("This is not an image file");
    }

    this.ListView.View = View.LargeIcon;
    this.imageList1.ImageSize = new Size(256, 144);
    this.ListView.LargeImageList = this.imageList1;

    for (int j = 0; j < this.imageList1.Images.Count; j++)
    {
        ListViewItem item = new ListViewItem();
        item.ImageIndex = j;
        this.ListView.Items.Add(item);
    }
}

我意识到我应该只根据需要填充缩略图但是...... a)我怎么知道列表视图中加载了多少项? b)如何在listview中检测滚动事件?

1 个答案:

答案 0 :(得分:0)

这很棘手。

你有两个问题:

  • 您需要知道需要显示哪些图像
  • 您需要确保不会耗尽内存或GDI资源

不幸的是,ListView对事件或属性没有任何帮助,可以通知您滚动或告诉您哪些项目可见。

这是一小段代码,至少会执行后者;它将几千个文件名加载到列表图像中并保留一个包含100个项目的列表,最后可见:

List<string> images = new List<string>();
List<int> visibleItems = new List<int>();

void listView1_DrawItem(object sender, DrawListViewItemEventArgs e)
{
    // this loads the images on demand:
    if (!imageList1.Images.ContainsKey(images[e.ItemIndex]) ) 
       { loadImage(e.ItemIndex); e.Item.ImageIndex = imageList1.Images.Count - 1; }
    // this makes sure the listView is drawn by the system
    e.DrawDefault = true;

    // these lines would maintain a list of items that are or were recently visible
    if (!visibleItems.Contains(e.ItemIndex)) visibleItems.Add(e.ItemIndex);
    if (visibleItems.Count > 1000)
    {
       visibleItems.Clear(); 
       imageList1.Images.Clear();
       listView1.Invalidate();
    }

}

void loadImage(int index)
{
    imageList1.Images.Add(images[index], new Bitmap(images[index]) );
}

您需要设置ListView.OwnerDraw = true;;然后将调用DrawItem事件,在设置e.DrawDefault = true;之后,实际绘图将由系统完成。

但事件会一直告诉你哪些项目可见。

现在你可以确保你的ImageList中加载了相应的位图,或者那些远处的位图再次处理..到目前为止,我只是按需加载..

更新:像Plutonix一样,我进行了一些测试,可以加载3000张图像,每张128x128像素,完全没有问题。我按需加载它们似乎ImageList非常好地处理事情:无需处理图像,GDI资源保持在我的最佳程序的低级别(<100)。当我滚动时,记忆保存器不断上升,但看起来并不像是一个问题。我只能做一个

imageList1.Images.Clear();

..并且内存回落到起点。显示工作正常,重新加载列表开始没有毛刺..实际上我不再使用visibleItems列表。我把它保留在答案中,因为这是了解这些物品的可行方法,但我认为没有必要......