Bonjour,
je réalise un gestionnaire de contacts en C# dont voici l'interface :
J'ai une fonction qui lors du clic sur le bouton "modifier" va récupérer les infos du contact sélectionné dans la ListBox, les transposer dans les champs texte correspondants, supprimer ce contact de la collection, puis réactiver le bouton "Ajout" afin d'ajouter le contact dont les infos ont été modifiées. La voici :
Cette fonction appelle une autre fonction qui va mettre à jour la ListBox en la vidant puis la remplissant de tous les contacts présents dans ma collection suite à un ajout, une modif ou une suppression de contact. La voici :
Mon problème est que lorsque je teste une modification, les infos du contact sélectionné sont bien transposées dans les champs texte, ce contact est bien supprimé de la collection mais suite à l'appel de majListe() la boucle foreach() continue à rechercher un contact qui du coup n'existe plus et le programme m'envoie l'erreur "System.InvalidOperationException : 'La collection a été modifiée ; l'opération d'énumération peut ne pas s'exécuter.'"
Quelqu'un aurait-il une idée d'où vient le problème ? je sèche
Si besoin je peux mettre le code dans les balises.
PS: Je débute donc tous les commentaires constructifs sur mon code, indentation, etc... sont les bienvenus
Bonjour
1) ne jamais supprimer ou ajouter un élément d'une liste pendant que tu la parcours
2) c'est pas la bonne façon de faire, pas besoin de supprimer et de remettre l'élément dans la liste, tu as juste à modifier les valeurs sur ton objet et comme ta liste contient une référence sur cet objet celui-ci sera à jour à l'intérieur.
3) j'avais pas vu ton lstcontact.selecteditem ==
tu peux faire plus simple et casté directement ton lstcontact.selecteditem en contact
ma préférence va au as pour les objets
https://coderwall.com/p/18dgtg/using-as-and-is-for-safe-casting-in-c
et tu peux copier/coller le code sur le site dans une citation si le block code marche pas, c'est plus simple pour nous qu'un screen
Salut Boucif,
1) Il me semblait que c'était foireux, je vais trouver un autre moyen.
2) En fait le prog est pour un TP et la prof demande qu'on supprime et recharge tous les contacts c'est pour cela.
3) Je vais me pencher sur les is / as afin de bien comprendre lequel s'adapte à quel cas.
Merci pour les réponses, je savais qu'en mettant "C#" dans le titre j'allais t'aggro
Mdr c'est mon langage de prédilection voila + 10 ans que j'en fais
l'idée c'est de supprimer les éléments après coup, en stockant les éléments à supprimer dans une autre liste dans ton foreach, et après parcourir cette nouvelle liste et supprimer dans la liste initiale par exemple (we ça peut être chiant), après il y a d'autre façon de faire je ne vais pas toutes te les énumérer
Du coup j'ai fait comme ca :
je stock l'indice du contact à modifier une fois trouvé dans la boucle, une fois la boucle terminée (je vais optimiser pour que ca boucle jusqu'à trouver le contact et non sur la liste entière) je supprime le contact, recharge la liste mise à jour dans la listbox puis l'utilisateur peut modifier les coordonnées du contact et l'ajouter à nouveau.
// Evènement sur clic du bouton Modifier
private void btnModifier_Click(object sender, EventArgs e)
{
// Si une ligne est bien sélectionnée
if (lstContacts.SelectedIndex != -1)
{
// Stockage (via index) du contact à supprimer
int index = 0;
// Recherche dans la collection du contact sélectionné dans la listbox
foreach (var contact in lesContacts)
{
// MAJ des champs nom, prenom, tel avec les infos du contact sélectionné
if (lstContacts.SelectedItem.ToString().Equals(contact.infosContact()))
{
txtNom.Text = contact.getNom();
txtTel.Text = contact.getTel();
rdbPro.Checked = true;
if (contact is Particulier)
{
txtPrenom.Text = ((Particulier)contact).getPrenom();
rdbParticulier.Checked = true;
}
index = lesContacts.IndexOf(contact);
}
}
// Suppression du contact puis MAJ de la listbox et activation des champs
// Pour nouvel ajout.
lesContacts.RemoveAt(index);
majListeSimple();
enable(true);
}
}
Perso je débute, j'ai touché un peu au C++, java, C#, javascript, php et je préfère de loin utiliser le C# même si avec l'expérience je changerai peut-être d'avis.
Fuck le php.
J’ai fais un peu de java, bcp de c# et du js, php je veux même pas en entendre parler 🤣
En passant js aussi c’est merdique.
Je check ton code, je pense il y a plus simple
public partial class Form1 : Form
{
List<Contact> lesContacts = new List<Contact>();
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
// Si une ligne est bien sélectionnée
Contact contact = listBox1.SelectedItem as Contact;
if (contact != null)
{
nomTextEdit.Text = contact.Nom;
prenomTextEdit.Text = contact.Prenom;
telTextEdit.Text = contact.Tel;
lesContacts.Remove(contact);
UpdateList();
}
}
private void button2_Click(object sender, EventArgs e)
{
var c = new Contact()
{
Nom = nomTextEdit.Text,
Prenom = prenomTextEdit.Text,
Tel = telTextEdit.Text
};
lesContacts.Add(c);
UpdateList();
}
private void UpdateList()
{
listBox1.Items.Clear();
foreach (var item in lesContacts)
{
listBox1.Items.Add(item);
}
}
}
public class Contact
{
public string Nom { get; set; }
public string Prenom { get; set; }
public string Tel { get; set; }
public override string ToString()
{
return $"{this.Nom} {this.Prenom}";
}
}
Button1 c'est modifier
Button2 c'est ajouter
TU peux travailler directement avec les objets étant donné que c'est la même référence à chaque fois
Il faut savoir qu'en C# (et je pense d'autre langage) tu as 2 types de donnée, les types valeurs et les types références
https://docs.microsoft.com/fr-fr/dotnet/csharp/language-reference/keywords/reference-types
https://blog.alphorm.com/type-valeur-et-type-reference-en-c/
C'est bon a connaitre mais pas sur que tu comprenne cette notion en tant que débutant mais très utile pour dev en c# de la meilleure façon possible.
Intéressant le cast avec le "as" effectivement ca simplifie les choses surtout qu'on ne se sert que d'un objet après et pas de plusieurs variables de types différents.
Sur le blog que tu as link,
il faut spécifier son type ou utiliser le mot clé var pour permettre au compilateur de déduire le type."
On peut déclarer toutes les variables en tant que var et le compilateur va déduire les types parfaitement derrière ? ca me parait gros
C'est super intéressant en tout cas les 2 types de variables existants et les répercussions sur la mémoire et donc la performance de l'appli.
Mais effectivement c'est un peu flou.
En gros ce que je comprends c'est que l'emplacement mémoire d'une variable de type valeur stock 1 donnée (1, "lol", etc...) tandis que celui d'une variable de type référence ne stock qu'une adresse. Mais les données sont bien stockées quelque part...ca implique donc 2 emplacements mémoire, 1 pour l'adresse du véritable stockage des données et 1 pour ce stockage ? Je n'y vois plus trop clair....
Je t'avoue que j'avais étudié le mot clé "ref" utilisé lors d'appels de fonctions avec certains paramètres et j'avais bien compris le principe mais là je ne sais plus quoi comprendre....
http://blog.algowin.fr/2018/10/29/csharp-pile-tas-memoire/
Oui t’étais pas loin, une fois que tu maitrises ces notions, tu fais du meilleur code, plus concis et plus juste en espérant que tu mettes pas le mot cle ref de partout 😂
Sinon tu mets juste un break après avoir modifier ta liste