如何根据需要在列表视图中加载缩略图

本文关键字:视图 加载 略图 列表 何根 | 更新日期: 2023-09-27 18:27:34

所以我希望能够基于图像文件路径列表填充1000个缩略图。我尝试使用以下代码,但我意识到在200多个图像之后,我的程序会向我抛出"System.Drawing.dll中发生了类型为"System.OutOfMemoryException"的第一次机会异常"。

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) 如何在列表视图中检测滚动事件?

如何根据需要在列表视图中加载缩略图

这相当棘手。

你有两个问题:

  • 您需要知道需要显示哪些图像
  • 您需要确保不会耗尽内存或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;;则将调用CCD_ 3事件,并且在设置CCD_。

但该事件将不断告诉您哪些项目是可见的。

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

更新:像Plutonix一样,我已经运行了一些测试,可以加载3000个128x128像素的图像,而没有任何问题。我按需加载它们,看起来ImageList处理得很好:不需要处理图像,GDI资源对我的thest程序来说保持在较低水平(<100)。当我滚动时,内存foorprint一直在上升,但看起来不会有问题。它是我可以简单地做一个

imageList1.Images.Clear();

并且记忆下降回到起点。显示工作正常,重新加载列表开始时没有出现故障。。事实上,我不再使用visibleItems列表了。我把它保留在答案中,因为这是了解这些项目的可行方法,但我认为没有必要。