[C#] Mehrfachauswahl und Löschen funktioniert nicht richtig

Cyperfriend

Der ohne Avatar
Registriert
14 Juli 2013
Beiträge
1.123
Ich arbeite immer noch fleißig an den Übungen und versuchte einmal mehr eine zu erweitern. Eigentlich wird in dem Buch nur gezeigt, wie ich mir die Mehrfachauswahl in einem Listenfeld als Text anzeigen lassen kann. Da aber im vorangegangenem Beispiel bereits ein Programm geschrieben wurde mit dem man (einzelne) Einträge löschen kann wollte ich direkt dieses Programm erweitern und mehrere Einträge auf einmal löschen (anstatt die mir nur in einem Text anzeigen zu lassen)

Die Eigenschaft "SelectionMode" ist auf "MultiSimple" gestellt ("MultiExtended" führt zum gleichen Ergebnis)
Mit dem folgenden Code wird bei einer einfachen Auswahl immer der oberste Eintrag gelöscht und bei einer mehrfachen Auswahl irgendwie je nach Anzahl der ausgewählten Elemente zwei bis drei Einträge. Habs aber nicht ganz kapiert. Jedenfalls funktioniert es so halt nicht. Hier mal der Code. Wäre toll, wenn mir jemand sagt wo der Fehler liegt.

[src=csharp]
private void cmdElementLoeschen_Click(object sender, EventArgs e)
{
int x = lstSpeisen.SelectedIndex;
if (x != -1)
{
for (x = 0; x < lstSpeisen.SelectedItems.Count; x++)
{
lstSpeisen.Items.RemoveAt(x);
}
}

}[/src]


Edit: Falls jemand das Tool nachschreiben möchte, hier der Code um das Listenfeld schnell zu füllen:
[src=csharp]
private void Form1_Load(object sender, EventArgs e)
{
lstSpeisen.Items.Add("Spaghetti");
lstSpeisen.Items.Add("Grüne Nudeln");
lstSpeisen.Items.Add("Tortellini");
lstSpeisen.Items.Add("Pizza");
lstSpeisen.Items.Add("Lasagne");
}[/src]
 
wenn du eine Menge { a, b, c, d, e } hast

dann hat c den Index 2 und d den Index 3

löscht du nun c, dann hat nun d den Index 2. Da liegt die Problematik. In dem Beispiel mit der Ausgabe verändert sich der Index von den Elementen nicht
 
Du mußt die 2 Listen trennen, die Liste mit allen Elementen und die Liste mit den selektierten.

Du löschte jetzt momentan aus der Liste so viele Elemente, wie Du gewählt hast. Also egal welche 3 Du wählst, immer die ersten 3.

Beim Löschen aus Listen muß man auch bedenken, daß man durch Wegnahme eines Elementes den Index zerstört.

Eine Möglichkeit wäre jetzt hier von Hinten zu löschen.

dies sollte funktionieren:

[src=csharp] for (x = lstSpeisen.SelectedItems.Count-1; x >=0 ; x--)
{
lstSpeisen.Items.Remove(lstSpeisen.SelectedItems[x]);
}[/src]
 
Schau dir nocheinmal genau an, was deine Schleife hier macht.

Du verwendest RemoveAt um einen Listeneintrag an einer bestimmten Stelle in deiner Listbox zu entfernen. Wenn du zum Beispiel deine Tortellini loeschen moechtest, wuerde der Aufruf lauten:

[src=csharp]lstSpeisen.Items.RemoveAt(2);[/src]

Willst du die Spaghetti loeschen, waere das:

[src=csharp]lstSpeisen.Items.RemoveAt(0);[/src]

So weit alles klar? Schauen wir uns deine Schleife an. Um die Anzahl der Durchlaeufe zu begrenzen verwendest du

[src=csharp]lstSpeisen.SelectedItems.Count[/src]

Was liefert diese Funktion genau zurueck? Sie gibt die Anzahl der ausgewaehlten Listbox Items. Wenn du 3 Eintraege in deiner Listbox ausgewaehlt hast, liefert sie 3. Hast du einen Item selektiert, bekommst du 1 und wenn nichts ausgewaehlt ist, liefert sie folglich 0.

Schauen wir also auf deine gesamte Schleife, was tut sie wenn wir 3 beliebige Eintraege ausgewaehlt haben und den Button klicken?

[src=csharp]for (x = 0; x < lstSpeisen.SelectedItems.Count; x++)[/src]

lstSpeisen.SelectedItems.Count hat den Wert 3. Die Schleife wird so lange wiederholt, bis x maximal 2 ist.

Denken wir uns jetzt den Ablauf in der Schleife Schritt fuer Schritt durch.

Am Beginn haben wir Spaghetti auf Platz 0 in der Listbox. Gefolgt von "Grune Nudeln" auf Platz 1 und "Tortellini" auf Platz 2 und die Pizza auf Stelle 3.

0 - Spaghetti
1 - Gruene Nudeln
2 - Tortellini
3 - Pizza
4 - Lasagne

Im ersten Durchlauf deiner Schleife ist X = 0. Dadurch wird der erste Eintrag in der Listbox, Spaghetti, geloescht. Alle weiteren Eintraege rutschen dadurch in deiner Liste nach oben, wodurch "Gruene Nudeln" jetzt auf Platz 0 sind. "Tortellini" rueckt vor auf Platz 1 und die Pizza ist auf Platz 2. Unsere Liste sieht also so aus:

0 - Gruene Nudeln
1 - Tortellini
2 - Pizza
3 - Lasagne

Jetzt kommt der zweite Durchlauf deiner Schleife. x hat dann den Wert 1 und RemoveAt loescht also den Listbox Eintrag auf Stelle 1, das sind die "Tortellini". Der Item auf Platz 0, Gruene Nudeln, bleibt davon unberuehrt. Die Tortellini sind weg und die Pizza rutscht weiter nach vorne auf Platz 1.
Nach den beiden vorherigen Schleifendurchlaeufen sieht unsere Liste in etwa so aus:

0 - Gruene Nudeln
1 - Pizza
2- Lasagne

Im naechsten und letzten Loop hat x den Wert 2 und es wird die Lasagne geloescht. Uebrig bleiben die Gruenen Nudeln und die Pizza.

Du hast also 2 Probleme auf die du achten musst:

Nummer 1:

Werden Listeneintraege entfernt, dann ruecken die nachfolgenden Eintraege vor und Ihr jeweiliger Index veraendert sich. In unserem Beispiel hatte die Pizza z. B. am Beginn unserer Schleifendurchlaeufe den Index 3 und am Ende den Index 1. Das bedeutet, dass die Indizes, die du dir am Beginn der Loesch-Schleife holst, nach dem loeschen eines Eintrags nicht mehr gueltig sind.
Die Loesung ist ganz einfach, du entfernst die Eintraege in umgekehrter Reihenfolge, also vom hoechsten bis zum niedrigsten Eintrag. Dadurch bleiben die urspruenglichen Indizes erhalten.

Nummer 2:

Du holst dir am Beginn deiner Funktion den ersten selektierten Listbox Eintrag. Dann pruefst du zwar, ob es ueberhaupt eine Auswahl gibt (!= -1) aber danach verwendest du den Index nicht. Du sagst nur, dass x zwischen 0 und 2 sein darf und loescht dann die Items mit diesen Indizes (0, 1, 2) wie oben beschrieben.

[src=csharp]int x = lstSpeisen.SelectedIndex;[/src]

Ueberleg dir, welcher Wert in x stehen wuerde, wenn jemand die Spaghetti auswaehlt; es waere 0. Waehlt jemand die Pizza, bevor er auf den Delete Button klickt, dann haette x den Wert 3.

Was du eigentlich moechtest ist eine Liste der Indizes aller ausgewaehlten Listbox Eintraege:

[src=csharp]lstSpeisen.SelectedIndices[/src]

Danach loopst du von hinten nach vorne durch diese Index Liste und loescht die Eintraege mit dem jeweiligen Index und nicht mit dem Schleifen-Zaehler der in x gespeichert ist.

Schau dir einmal an. Hab hier leider keinen C# Interpreter installiert um den Code zu testen, aber fuer dich sollte in etwa soetwas funktionieren:

[src=csharp]private void cmdElementLoeschen_Click(object sender, EventArgs e)
{
//x wird von oben nach unten durchgezaehlt
for(int x = lstSpeisen.SelectedIndices.Count - 1; x>= 0; x--)
{
//idx bekommt den Wert, der an
//der Stelle x in unserer Index Liste steht.
int idx = lstSpeisen.SelectedIndices[x];
//der Eintrag mit dem Index wird aus der Liste geloescht.
lstSpeisen.Items.RemoveAt(idx);
}
} [/src]

Ist dir klar warum SelectedIndices.Count - 1 verwendet wird? Bei drei ausgewaehlten Eintraegen wuerde Count die Zahl 3 zurueck liefern. Bei der Nummerierung unserer Indizes wird aber bei 0 zu zaehlen begonnen. Das heisst, der 3. Listeneintrag haette den Index 2, der erste Eintraeg liegt bei 0.

Hoffe das ist einigermassen verstaendlich. Ist gar nicht einfach zu erklaeren, wenn man betriebsblind ist.

<3
 
  • Thread Starter Thread Starter
  • #5
Danke für die ausführliche Erklärung. Das der Index mit Null beginnt wusste ich schon, aber dass der Index entsprechend immer eins nach vorne rutscht und wie man das behandelt nicht. Das hätte die in dem Buch aber ruhig mal erklären können, weil da steckt ja schon etwas mehr dahinter als nur ein Einträge zu löschen und auch mehr als sich alle markierten Einträge in einem Lael anzeigen zu lassen.

Danke euch jedenfalls
 
Zurück
Oben