0
votes

I have a ListView which I populate with the contents of an ImageList. When an Item is selected from the list, I check if the file still exists. If it doesn't, I want to remove it both from the Image List (which is private static) and from the ListView. For some strange reason, which I can't figure out, after removing the selected image from the list, the image right after it disappears and the last image in the list appears twice. For example, if the list held the following images: IMG1, IMG2, IMG3, IMG4, IMG5 and I remove IMG2 the new list will look like this: IMG1, IMG4, IMG5, IMG5.

Furthermore, if I select the second image from the list (which is now IMG4) and display it in some picture control, IMG3, which was supposed to be in that place will be displayed in the control.

Any ideas what's going on here?

EDIT: Populating the List view:

private static ImageList stampsImages

        if (stampsImages == null)
        {
            stampsImages = new ImageList();
            stampsImages.ImageSize = new Size(125, 75);
        }

        DirectoryInfo di = new DirectoryInfo(Globals.Directory);
        if (di.Exists)
        {
            FileInfo[] dFiles = di.GetFiles("*.png");
            int stampListSize = stampsImages.Images.Count;

            for (int i = 0; i < dFiles.Length; i++)
            {
                int idx = stampsImages.Images.IndexOfKey(dFiles[i].FullName);

                if (idx < 0)
                {
                    stampsImages.Images.Add(Bitmap.FromFile(dFiles[i].FullName));
                    stampsImages.Images[stampListSize].Tag = dFiles[i].FullName; 
                    stampsImages.Images.SetKeyName(stampListSize, dFiles[i].FullName);
                    stampListSize++;
                }
            }
        }
        else di.Create();

        for (int i = 0; i < stampsImages.Images.Count; i++)
        {
            ListViewItem stmp = new ListViewItem("", i);
            lvwStamps.Items.Add(stmp);
        }
        lvwStamps.LargeImageList = stampsImages;      

Checking if the file still exists:

    private bool IsStampAvailable(int listIdx)
    {
        bool stampExists = true;
        string stampFile = stampsImages.Images.Keys[listIdx];
        if (!File.Exists(stampFile))
        {
            lvwStamps.Items.RemoveAt(listIdx);
            stampsImages.Images.RemoveAt(listIdx);
            stampExists = false;
        }

        return stampExists;
    }
2
some code would probably be more useful than a description of what you think is happening. you are only going to describe what you expect your code to be doing, and not what it is actually doing, and if it was doing what you expect you wouldn't be here...Sam Holder
and it sounds like 0 based vs 1 based index issue.Sam Holder
Show us at least the removal code.Tim Schmelter
It's a WinForms project.Guy

2 Answers

0
votes

The problem is that the ListView items probably remember the index of the image in the ImageList. If you remove an image from the ImageList, the ListView items will point to a wrong image.

Try to reference the images by key instead of by index.


This is a test I made

imageList1.Images.Add("img0", Properties.Resources.img0); // Use key as first argument.
imageList1.Images.Add("img1", Properties.Resources.img1);
imageList1.Images.Add("img2", Properties.Resources.img2);
imageList1.Images.Add("img3", Properties.Resources.img3);
imageList1.Images.Add("img4", Properties.Resources.img4);
imageList1.Images.Add("img5", Properties.Resources.img5);
for (int i = 0; i < 6; i++) {
    var item = new ListViewItem(
        "Image #" + i, // Text
        "img" + i      // <== Use key here, not index
    );
    listView1.Items.Add(item);
}

If I remove an entry with ...

listView1.Items[1].Remove();
imageList1.Images.RemoveAt(1);

... it works correctly.

0
votes

Every time you remove an image from the ImageList, you'll have to decrement the ImageIndex of each ListViewItem that points to an ImageIndex equal or higher than the ImageIndex of the deleted image. Usually a linear decrement is sufficient starting at the index of the Item after deleted Item (if ImageList and ListViewItems keep a 1:1 relation):

for (int i = lvItem.Index + 1; i < listView1.Items.Count; i++)
    listView1.Items[i].ImageIndex--;

Maybe more important is to delete the items AFTER reindexing (after deleting a ListViewItem the ListView must repaint and indicies should be in the right order for this):

int iImageIndex = lvItem.ImageIndex;
int iIndex = lvItem.Index; 
for (int i = iIndex + 1; i < listView1.Items.Count; i++) // correct the image indicies
    listView1.Items[i].ImageIndex--;       
lvItem.Remove(); // repaint
Image img = ImageList1.Images[iImageIndex];
ImageList1.Images.RemoveAt(iImageIndex);
img.Dispose();