Appel générique d'une procédure commune à plusieurs classes [Résolu]

Messages postés
171
Date d'inscription
vendredi 1 septembre 2006
Statut
Membre
Dernière intervention
14 novembre 2019
-
Bonjour,

En VB6, j'avais l'habitude, pour synchroniser plusieurs fenêtre filles MDI, d'appeler dans un boucle une procédure dont le nom était commun à toutes les feuilles. Genre :
    For Each F In Forms
        If Not F Is wMain Then F.UpdateAll
    Next

Je précise que bien sûr ces feuilles sont différentes (sinon ce serait très simple), mais chacune présente une procédure publique nommée UpdateAll.

En C#, cela donnerait ceci, qui bien sûr ne fonctionne pas.
foreach (Form F in Application.OpenForms)
    if (!F.GetType().Equals(typeof(wMain)))
        F.UpdateAll();


En C#, il est normal que cela ne convienne pas au compilateur, car la procédure UpdateAll n'est pas reconnue pour la classe Form.
Je suppose qu'il faudrait une interface commune, mais je ne sais pas encore faire ça.
Une extension de la classe Form ?
Une implémentation d'interface ?
Une interception de la méthode Update() de Form ?
Ou autre chose...

Merci pour les conseils avisés.
Afficher la suite 

3 réponses

Messages postés
14037
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
10 décembre 2019
324
0
Merci
Bonjour

Avant tout, ça
if (!F.GetType().Equals(typeof(wMain)))
c’est trop compliqué
if(!(F is wMain))
et encore y’a p’tet même pas besoin du 2eme jeu de parenthèses, mais là j’ai pas de quoi tester.

Je pense qu’une solution est l’interface, car ça te simplifie à la fois le test et l’exécution.
Admettons que l’interface s’appelle Imgd.

if(F is Imgd)
((Imgd)F).UpdateAll();


Ou encore (encore moins de code)
Imgd ff = F as Imgd;
ff?.UpdateAll();


Plus d’info sur les opérateurs is, as et ?.
https://docs.microsoft.com/fr-fr/dotnet/csharp/language-reference/keywords/is

https://docs.microsoft.com/fr-fr/dotnet/csharp/language-reference/operators/type-testing-and-conversion-operators#as-operator

https://docs.microsoft.com/fr-fr/dotnet/csharp/language-reference/operators/member-access-operators#null-conditional-operators--and-

Ecrire une interface est assez simple.
C’est comme écrire une classe abstraite, sauf que le corps des méthodes est toujours vide.
Le paragraphe du cours de Tahé est assez explicite je pense
https://tahe.developpez.com/dotnet/csharp/?page=page_5#LV-F

Une autre option est d’abonner tes forms à un événement.
Au lieu d’appliquer ta méthode dans une boucle , tu déclenches l’événement et les forms concernées vont y réagir.
Commenter la réponse de Whismeril
Messages postés
171
Date d'inscription
vendredi 1 septembre 2006
Statut
Membre
Dernière intervention
14 novembre 2019
0
Merci
Ok pour le 'As'. Je connaissais déjà, grâce à toi dans un post datant de mes débuts en C# (à peine un an !).

Je connaissait 'Is' en VB6, pas en C#. Cependant hélas cela ne marche à priori que pour des types, pas pour des objets. En effet, si j'écris :
foreach(Form F in this.MdiChildren)
    if(F is wMachin)
        ...
Le compilateur ne génère pas d'erreur. Je suppose que si plusieurs instances de wMachin sont ouvertes, elles seront toutes concernées.

Par contre, si j'écris :
foreach(Control Ctrl in this.Controls)
    if(Ctrl is txtNom)
        ....
le compilateur m'annonce : "Une valeur de constante est attendue". Je dois donc passer par
if Ctrl.Equals(txtNom)
. A moins qu'il n'y ait une autre subtilité ??

J'avais pratiqué le polymorphisme et l'implémentation d'interface en VB6. Le concept ne m'est donc pas inconnu. J'ai jeté un œil sur le cours de Tahé, mais la première lecture n'est pas du tout concluante. Je n'ai pas trouvé la notion d'interface, mais celle de polymorphisme.
Je n'arrive pas à comprendre comment créer une interface et la relier à ma Form.
Pas de problème lorsqu'il s'agit de classes que l'on crée. Par contre, mes feuilles héritent de Form. Comment créer une méthode supplémentaire à la classe Form ?
Ou alors, créer une classe abstraite dérivant de Form, y créer une méthode virtuelle UpdateAll, et dériver mes feuilles de cette classe ? Je ne suis pas sûr que l'IDE de Visual Studio apprécie et me présente correctement l'aspect de ma feuille en mode création.

Tout ça demande encore pas mal de réflexion...
Je reviendrai... (comme Darkvador ;-) )
Whismeril
Messages postés
14037
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
10 décembre 2019
324 -
Non, je reviendrai c’est Terminator ;)
Whismeril
Messages postés
14037
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
10 décembre 2019
324 -
Oui is fonctionne pour un type, une interface, mais pour une constante aussi.

Pour tester si toto est txtNom, il suffit de
if(toto == txtNom)


Pour l’interface, c’est un truc dans ce genre (je suis avec ma tablette, donc je ne peux pas tester)
public interface Imgd
{
     public void UpdateAll();
}


Et pour formBidule qui doit implémenter cette interface
public formBidule: Form, Imgd


Et dans le corps de formBidule, tu écris updateAll()
Commenter la réponse de MGD Software
Messages postés
171
Date d'inscription
vendredi 1 septembre 2006
Statut
Membre
Dernière intervention
14 novembre 2019
0
Merci
Bonjour Whismeril,

Il doit me manquer une info...

J'ai bien déclaré une interface IUpdatable :
public interface IUpdatable
{
   void UpdateForm();
}


Dans mes feuilles, j'ai ajouté à la déclaration de classe la référence à IUpdatable :
public class MyForm : Form, IUpdatable


Dans la classe, j'ai placé une procédure
public void UpdateForm()
{
   ...
}

Mais quand je mets dans ma feuille MDI principale les lignes :
public void UpdateAll()
{
    foreach (Form F in MdiChildren)
        F.UpdateForm();
}

Le compilateur ne reconnait pas la méthode UpdateForm. Je suppose que c'est normal, car il ne sait pas que F dispose de l'interface IUpdatable.
Je suppose qu'il faut ajouter ou modifier la déclaration de F dans la boucle. J'ai tenté de remplacer Form par IUpdatable dans le foreach, mais cela ne marche pas : F.UpdateForm() ne provoque plus d'erreur, mais IUpdatable provoque une erreur "Type introuvable" Je précise que la déclaration de l'interface est bien située dans l'espace de nom commun à toutes les fenêtres.

Un conseil ?

PS : Pendant que j'écrivais, j'ai trouvé :
foreach (Form F in MdiChildren)
    ((IUpdatable)F).UpdateForm();

Bon sang, mais c'est bien sûr !
Je manque encore de réflexes C#...
Whismeril
Messages postés
14037
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
10 décembre 2019
324 -
Je te l’avais mis dans le message 1;)
Commenter la réponse de MGD Software