Пустое пространство появляется в верхней части ListView при удалении групп

Мой музыкальный проигрыватель использует ListView в режиме Details для отображения дорожек и ListViewGroup для группировки дорожек альбомов.

Я создал событие, которое удаляет все треки в одном альбоме, когда ListViewGroup альбома щелкается средней кнопкой мыши. Работает нормально, если ListView не прокручивается вниз при удалении дорожек. Если ListView прокрутить вниз, альбом будет удален, но в верхней части ListView между заголовками и первой группой появится большое пустое пространство, на которое нельзя щелкнуть.

Первое изображение, 3 альбома в ListView (прокручивается вверх)

введите здесь описание изображения


Второй образ, последний альбом удален, все нормально!

введите здесь описание изображения


Хорошо, тогда ListView прокручивается вниз при удалении одной группы элементов

Третье изображение, 3 альбома в ListView (прокрутка вниз)

введите здесь описание изображения


Четвертое изображение, последний альбом удален, вверху появилось пустое место, а последние треки, если ListView вообще не показывается!

введите здесь описание изображения


Я не думаю, что это имеет какое-то отношение к моему коду, а скорее к ошибке в ListView? Кто-нибудь замечал такое же поведение? Есть ли какой-нибудь трюк, чтобы этого не произошло?


РЕДАКТИРОВАТЬ: добавлен код, который удаляет элементы (по запросу пользователя)

List<ListViewItem> delItems = new List<ListViewItem>(); // creating list of items to be removed

foreach (ListViewGroup group in listView1.Groups)
{
    if (Convert.ToInt32(group.Tag) == groupNumber) // all groups have individual number in tag field
    {
        foreach (ListViewItem item in group.Items)
        {
            delItems.Add(item);
        }
    }
}

foreach (ListViewItem item in delItems)
{
    item.Remove();
}

EDIT2: добавлен код, чтобы проверить, была ли нажата группа

Поскольку нет реального способа обрабатывать групповой щелчок, я сделал это уродливым способом. Но это работает. Прежде всего, я использовал событие MouseDown в ListView. Затем я проверяю, есть ли элемент, на который нажимает пользователь. Если пользователь щелкает группу, то элемент равен нулю, а цикл for увеличивает i и проверяет, можно ли найти элемент сейчас. Когда в конце концов элемент найден, мы знаем, что элемент принадлежит группе, по которой мы щелкнули. Таким образом, мы получаем тег группы элементов, где я сохраняю запись о том, что это за группа.

private void listView1_MouseDown(object sender, MouseEventArgs e)
{
    ListViewItem item;

    for (int i = 0; i < 25; i++) // group height is not more that 25 pixels.
    {
        item = listView1.GetItemAt(e.X, e.Y + i);

        if (item != null)
        {
            if (i > 1) // bigger than 1, because there is 1 pixel gap between listviewitems when using groups
            {
                if (e.Button == MouseButtons.Middle) removePlaylistGroup(Convert.ToInt32(item.Group.Tag));
            }
            else
            {
                if (e.Button == MouseButtons.Middle) removePlaylistItem(item.Index);
            }
            break;
        }
    }
}

person darx    schedule 24.07.2014    source источник
comment
Можете ли вы воспроизвести его при запуске на другой машине? Я согласен с вашей оценкой, что это, вероятно, не что-то с вашим кодом, но я никогда не видел, чтобы это происходило раньше.   -  person CodingGorilla    schedule 25.07.2014
comment
Да, это происходит в другой Win7, а также в Win8.1.   -  person darx    schedule 25.07.2014
comment
@darx: Можете ли вы показать нам код, который удаляет элементы?   -  person TaW    schedule 25.07.2014
comment
@TaW: код добавлен к исходному вопросу.   -  person darx    schedule 25.07.2014


Ответы (1)


Все это происходило потому, что удаление элементов из ListView, по-видимому, запускает событие Form1_Layout. Там я использую listView1.BeginUpdate() ... для изменения размера listView1, если изменяется макет формы. Как-то это портит мой listView.

person darx    schedule 25.07.2014
comment
Я предлагаю обрамить цикл удаления парой listView1.SuspendLayout() - listView1.ResumeLayout(). Кстати, как вы ловите групповой клик? Я знаю, что могу создать подкласс ListView и переопределить WndProc, чтобы перехватить его; Однако я не знаю, как идентифицировать группу, на которую нажали..!? - person TaW; 25.07.2014
comment
Ничего общего с Suspend/ResumeLayout(). Диагностика здесь — отсутствующий вызов ListView.EndUpdate(). Но на самом деле не вызывайте BeginUpdate() в обработчике событий Layout. Его следует использовать только в том случае, если вы вносите массовые изменения в коллекцию Items. Если у вас есть проблемы с мерцанием, исправьте их, создав собственный класс из ListView и задав его свойству DoubleBuffered значение true в конструкторе. - person Hans Passant; 25.07.2014
comment
@TaW: я добавил код, чтобы показать, как определить групповой клик. Не стесняйтесь спрашивать, если вы не понимаете моего объяснения: P - person darx; 25.07.2014
comment
@HansPassant: я удалил beginupdate из Layout. Я решаю проблему мерцания, отфильтровывая сообщение WM_ERASEBKGND, поэтому фон не рисуется снова и снова, когда что-то происходит в списке. Работает отлично. Двойная буферизация тоже включена. - person darx; 25.07.2014
comment
Ох, надеюсь скоро увидеть вас снова с жалобой на плохо выглядящий текст в списке. - person Hans Passant; 25.07.2014
comment
@HansPassant: я использую его уже несколько недель, и никаких проблем. Все нарисовано правильно, мерцания нет вообще. - person darx; 25.07.2014
comment
@darx: Спасибо за код. Уродливый? Да, но это работает. По крайней мере, пока вы не нажимаете на SubItems.. - person TaW; 25.07.2014
comment
@TaW: я использую подэлементы, как вы можете видеть на скриншотах. Вы можете свободно нажимать на них. Если вы щелкнете по группе, запустится метод removePlaylistGroup(), а при нажатии на элементы/подэлементы запустится метод removePlaylistItem(). Так что пока без проблем :) - person darx; 25.07.2014