Удаление ListViewItem с изображением из ListView

Я пытаюсь динамически изменить ListView в моей программе. Каждый предмет имеет ImageKey и я использую SmallImageList для них.

Проблема заключается в том, что всякий раз, когда я удаляю элемент, возникает проблема, которая была упомянута в этом вопросе:

До и после удаления элемента:

ДоПосле

Используемый код:

// 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);
}

Ответ в вопросе (который рекомендует не удалять изображения из ImageList) не соответствует моим требованиям, потому что я добавляю элементы с одинаковыми ImageKey после удаления, значит, более одного Imageв SmallImageList.Images получить то же самое ImageKey, поэтому изображения становятся противоречивыми. Также ответ игнорирует очевидную утечку памяти.

2 ответа

Решение

К сожалению удаление Image от ImageList действительно вызывает индексы Items двигаться вверх. Это означает, что внутренне Keys больше не используются, но отображаются на индексы при добавлении или настройке, а затем больше не сохраняются.

Так что обойти можно либо..

  • Сохранить все Images в ImageList и жить с ненужным Images, В 256x256 пикселей x 4 байта Image может иметь только 256 КБ, поэтому трата памяти не будет такой большой. (Обратите внимание, что ресурсы GDI+ не расходуются впустую, так как ImageList не создает никаких ручек для его Images.) Но учитывая достаточное добавление / удаление растущего размера ImageList может стать проблемой..

  • Или вы можете обойти, сохраняя и сбрасывая ImageKeys,

Вот пример:

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();

}

Чтобы это работало, вам нужно хранить правильные строки ключей. Я решил сделать это в IListViewItem.Tag имущество. Вы можете сделать это при добавлении Items или прямо перед удалением:

foreach (ListViewItem xItem in listView1.Items)
        xItem.Tag = xItem.ImageKey;               // (*)

Я думаю, что проблема в том, что вы пытаетесь изменить список в цикле foreach. Я бы рекомендовал сначала сделать цикл и запомнить выбранные элементы, которые вы хотите удалить, в новом списке, а затем в следующем цикле удалить их. Таким образом, вы не будете редактировать список, который вы зацикливаете.

Другие вопросы по тегам