La raccolta è stata modificata; l’enumerazione non può eseguire errori durante la rimozione di un ListItem da un LIstBox

Ho due ListBox, lstAvailableColors e lstSelectedColors. Tra ogni listbox ci sono due pulsanti, Aggiungi e Rimuovi. Quando si seleziona un colore o un colore in lstAvailableColors e si fa clic sul pulsante Aggiungi, voglio rimuoverli da lstAvailableColors e visualizzarli in lstSelectedColors. Inoltre, se i colors sono selezionati in lstSelectedColors e si fa clic sul pulsante Rimuovi, voglio rimuovere i colors da lstSelectedColors e aggiungerli nuovamente a lstAvailableColors. Quando faccio questo, ottengo il seguente errore quando rimuove l’object:

La raccolta è stata modificata; l’operazione di enumerazione potrebbe non essere eseguita.

Ecco il codice per il pulsante Aggiungi e il pulsante Rimuovi:

Inserisci:

protected void btnAdd_Click(object sender, EventArgs e) { foreach (ListItem item in lstAvailableColors.Items) { if (item.Selected) { lstSelectedColors.Items.Add(item); lstAvailableColors.Items.Remove(item); } } } 

Rimuovere:

 protected void btnRemove_Click(object sender, EventArgs e) { foreach (ListItem item in lstSelectedColors.Items) { if (item.Selected) { lstAvailableColors.Items.Add(item); lstSelectedColors.Items.Remove(item); } } } 

Non è ansible modificare una raccolta mentre la si enumera in .Net. Devi separare la tua enumerazione e rimuovere il codice in diversi blocchi. Ecco un breve esempio su come farlo senza LINQ

 protected void btnAdd_Click(object sender, EventArgs e) { var selected = new List(); foreach (ListItem item in lstAvailableColors.Items) { if (item.Selected) { selected.Add(item); lstSelectedColors.Items.Add(item); } } foreach (ListItem item in selected) { lstAvailableColors.Items.Remove(item); } } 

Ed ecco una versione più concisa usando LINQ

 var selected = lstAvailableColors.Cast().Where(i => i.Selected).ToList(); selected.ForEach( x => { lstSelectedColors.Items.Add(x); }); selected.ForEach( x => { lstAvailableColors.Items.Remove(x);}); 

MODIFICARE

La versione LINQ funziona in due parti. La prima parte è la prima riga che trova gli elementi attualmente selezionati e memorizza il valore in un List . È molto importante che la riga contenga la chiamata .ToList () perché forza l’esecuzione della query immediatamente rispetto all’esecuzione ritardata.

Le due righe successive eseguono l’iterazione di ciascun valore selezionato e lo rimuovono o aggiungono all’elenco appropriato. Poiché la lista selezionata è già stata archiviata, non lo si elabora più quando lo modifichiamo.

Non è ansible modificare una raccolta mentre si sta utilizzando un Enumeratore per questa raccolta, cosa fa per ogni istruzione.

È necessario eseguire il looping dei dati con un ciclo for normale e quindi è ansible modificare la raccolta, ma è necessario fare attenzione ad aggiornare correttamente l’indice corrente se si inseriscono o si rimuovono elementi. Se si aggiungono o rimuovono elementi e non ne inseriscono alcuni, l’iterazione dall’ultimo elemento al primo verrà eseguita.

 protected void btnAdd_Click(object sender, EventArgs e) { for (Int32 i = lstAvailableColors.Items.Count; i >= 0; i--) { ListItem item = lstAvailableColors.Items[i]; if (item.Selected) { lstSelectedColors.Items.Add(item); lstAvailableColors.Items.Remove(item); } } } 

Non è ansible modificare una raccolta su cui si sta iterando. In generale, una buona soluzione per questo tipo di problema è creare una raccolta vuota e, nel proprio iteratore, copiare su tutti gli elementi che NON si desidera rimuovere; dopo aver completato l’iterazione, sostituire la raccolta originale con la nuova raccolta.

Come l’altra risposta menzionata, non puoi rimuovere gli elementi fino a quando non hai completato l’iterazione. Quindi forse qualcosa del genere sarà più pulito per te:

 var itemsToRemove = lstAvailableColors.Items.Cast().Where(i => i.IsSelected).ToArray(); foreach(ListItem item in itemsToRemove) lstAvailableColors.Remove(item); 

Non è ansible modificare una raccolta mentre si sta iterando su di essa. O itera su una copia o usa per, itera in ordine inverso e rimuovi mentre vai giù.

Esempio su come rimuovere gli articoli selezionati. Qui vengono presi e rimossi solo gli indici selezionati.

  public void RemoveSelectedItems(ListBox listbox) { List items = GetSelectedItems(listbox); foreach (var listItem in items) { listbox.Items.Remove(listItem); } } public List GetSelectedItems(ListBox listbox) { int[] selectedIndices = listbox.GetSelectedIndices(); return selectedIndices.Select(index => listbox.Items[index]).ToList(); } 

Forse questo è ciò di cui hai bisogno

 protected void btnAdd_Click(object sender, EventArgs e) { while(listBox1.SelectedIndex!=-1) { listBox1.Items.Remove(listBox1.SelectedItem); } } 

Questo potrebbe aiutarti;

Rimuovere:

 protected void btnRemove_Click(object sender, EventArgs e) { { for (int i = 0; i < lstAvailableColors.Items.Count; i++) { if(lstAvailableColors.Items[i].Selected) lstAvailableColors.Items.RemoveAt(i); } } } 

Il problema che affronti è che non puoi modificare la raccolta che stai pubblicando. Puoi risolvere questo problema usando un singolo linq:

 protected void btnAdd_Click(object sender, EventArgs e) { lstAvailableColors.Items.RemoveAll(ac => ac.Selected); }