问题
I'm trying to dynamically change a ListView
in my program. Every item has an ImageKey
and I use a SmallImageList
for them.
The problem is whenever I delete an item, the problem which was mentioned in this question appears:
Before and after deleting an item:
Code used:
// Add the images from an array of paths foreach (string xFile in files) { thumbnails_imageList.Images.Add(xFile, images[xFile]); files_lst.Items.Add(xFile, Path.GetFileNameWithoutExtension(xFile), xFile); } // Delete the selected key(s) foreach (ListViewItem xItem in files_lst.SelectedItems) { files_lst.Items.Remove(xItem); thumbnails_imageList.Images.RemoveByKey(xItem.Name); }
The answer in the question (which recommends not to remove images from the ImageList
) doesn't meet my requirements because I add items with the same ImageKey
after removing, so, more than one Image
s in SmallImageList.Images
get the same ImageKey
, therefore images become inconsistent. Also the answer ignores the obvious memory leak.
回答1:
Unfortunately the removal of an Image
from the ImageList
indeed causes the indices of the Items
to move up. This means that internally the Keys
are no longer used but are mapped to the indices when adding or setting and then no longer kept intact.
So to workaround you can either..:
Keep all
Images
in theImageList
and live with the unnecessaryImages
. At 256x256pixels x 4 byte anImage
can have only 256k, so the memory waste will not be so big. (Note that no GDI+ resources are wasted, since anImageList
doesn't create any handles for itsImages
.) But given enough adding/removing the growing size of theImageList
may become a problem..Or you can work around by storing and resetting the
ImageKeys
.
Here is an example:
private void DeleteButton_Click(object sender, EventArgs e)
{
foreach (ListViewItem xItem in listView1.SelectedItems)
{
// maybe insert the loop below here (*)
listView1.Items.Remove(xItem);
// only delete when no longer in use:
string key = xItem.ImageKey;
if (listView1.Items.Cast<ListViewItem>().Count(x => x.ImageKey == key) == 0)
imageList1.Images.RemoveByKey(key);
}
// after deletions, restore the ImageKeys
// maybe add a check for Tag == null
foreach (ListViewItem xItem in listView1.Items)
xItem.ImageKey = xItem.Tag.ToString();
}
For this to work you need to store the correct key strings. I chose to do so in the IListViewItem.Tag
property. You can do it when adding the Items
or right before the deleting:
foreach (ListViewItem xItem in listView1.Items)
xItem.Tag = xItem.ImageKey; // (*)
回答2:
I think the problem is that you try to modify list in the foreach loop. I would recommend first make a loop and remember the SelectedItems you want to delete in new list and then in the next loop delete them. This way you won't edit the list you are looping.
来源:https://stackoverflow.com/questions/39916598/removing-listviewitem-with-image-from-listview