Проблема выбора элемента C# ListView после удаления элемента

Использование Visual Studio 2008, .Net 3.5

У меня есть ListView, загруженный кучей элементов. У меня есть всплывающее окно для удаления элемента. После удаления элемента я перерисовываю представление списка, повторно обращаясь к своим первичным данным, и сбрасываю выбранный элемент. Однако выбранный элемент не отображается как выбранный.

Идея кода:

public ListView m_lv;  
public MyDataCollection m_Data;  // Has a function to get data based on a tag.  

public void RemoveEventHandler(object sender, EventArgs e)  
{  
  int iSelectedItem= m_lv.FocusedItem.Index;

  int iDataIndexToRemove= m_Data.GetIndexOf(m_lv.FocusedItem.Tag.ToString());  

  m_Data.RemoveAt(iDataIndexToRemove);  // Remove the item.  

  if(0 != m_lv.Items.Count)  
  {  
    if(iSelectedItem == m_Data.Items.Count)  // Removed last.  
      iSelectedItem= m_Data.Items.Count - 1;  
  }

  m_lv.Items.Clear();  // Clear the list view items.  

  // Completely rebuild the list view.  
  foreach(MyData md in m_Data)  
  {  
    ListViewItem lvi= new ListViewItem(md.Column0.ToString());  
    lvi.SubItems.Add(md.Column1.ToString());  
    lvi.SubItems.Add(md.Column3.ToString());  
    lvi.SubItems.Add(md.Column4.ToString());  

    m_lv.Items.Add(lvi);  
  }  

  // Set up tags, column sizes, etc.  

  if(0 != m_lv.Items.Count)  
    m_lv.Items[iSelectedItem].Selected= true;  // Set the selection.      
}  

Если я сделаю что-то подобное выше, выбранный элемент никогда не будет отображаться визуально как выбранный (без изменения цвета фона), если только я не изменю размер столбца или сортировку. Затем он отображается как выбранный. Однако, если я использую отладчик или добавляю кнопку, чтобы использовать окно сообщения для отображения выбранных элементов, элемент знает, что он выбран.

Я знаю, что это какая-то проблема обновления/рисования - есть идеи?


person GTAE86    schedule 17.02.2010    source источник


Ответы (4)


Похоже, что ваш ListView не имеет фокуса из-за всплывающего окна, вызываемого правой кнопкой мыши, и для HideSelection установлено значение true. Это будет означать, что пока ваш элемент выбран, WinForms не отображает его. Сначала отключите HideSelection, чтобы проверить, затем вам понадобится код, чтобы вернуть фокус на список.

Кроме того:

  1. Если вы используете ListView.Items.Clear(), вы не потеряете столбцы, и поэтому вам придется каждый раз добавлять их заново (что будет раздражать пользователей, которые изменили размеры заголовков столбцов).
  2. Не делайте всю чистку и обновление. Установите каждое свойство Name ListViewItem в качестве первичного ключа, затем вы можете сделать ListViewItem liToRemove = listView[name];
person Neil Barnwell    schedule 17.02.2010
comment
Вы были правы — для свойства HideSelection было установлено значение false. Похоже проблема в фокусе. Примечание. Я использую ListView.Items.Clear(), чтобы очищать только элементы, а не столбцы. Я не уверен, что вы имеете в виду со свойством ListViewItem Name. Я думаю, вы имеете в виду просто удалить элемент из представления и соответствующий элемент данных из набора данных. Изначально я так и делал, но столкнулся с проблемой обновления и решил перерисовать все элементы. Спасибо за помощь! - person GTAE86; 18.02.2010

После установки выбора попробуйте вызвать метод Invalidate в ListView.

person Jacob Seleznev    schedule 17.02.2010

Использовать этот:

m_lv.BeginUpdate();

// Add the items

m_lv.EndUpdate();
//
if(0 != m_lv.Items.Count)  
    m_lv.Items[iSelectedItem].Selected= true;  // Set the selection.   

Не вызывайте «Invalidate», использование Begin/End Update должно предотвратить мерцание и обновление...

Редактировать: Чтобы объяснить причину моего утверждения... BeginUpdate замораживает все сообщения WM_PAINT...EndUpdate размораживает WM_PAINT, благодаря этому добавление элементов в список появляется намного быстрее, и в любом случае после вызова EndUpdate он обновится! Выбор может быть любым, я предпочитаю помещать его вне EndUpdate... это мое мнение... Invalidate генерирует сообщение WM_PAINT, но не обязательно обрабатывается сразу... Было бы нецелесообразно вызывать Invalidate() в цикл, в котором элементы добавляются, так как обновление замедляется!

Надеюсь, это поможет. С уважением, Том.

person t0mm13b    schedule 17.02.2010
comment
Что не так с Invalidate? И как Begin/EndUpdate помогает решить проблему с обновлением? Разве тогда EndUpdate не должен быть после установки выбора? - person Jacob Seleznev; 18.02.2010

В итоге получилось довольно просто:

// Figure out index of item to remove, iRemoved, do some work....  

m_lv.Items.RemoveAt(iRemoved);  
m_lv.Refresh();

// Figure out what is left so new selection, iNewSelection, can be set....
m_lv.Items[iNewSelection].Selected = true;  

Забыл, что не обновил этот пост!

person GTAE86    schedule 05.10.2011