Question

Je me suis un peu reculé dans un coin ici.

J'ai une série de contrôles utilisateur hérités d'un parent, qui contient quelques méthodes et événements pour simplifier les choses, de sorte que je n'ai pas à écrire de lignes et de lignes de code presque identique. Comme tu fais. Le parent ne contient pas d'autres contrôles.

Ce que je veux faire, c’est avoir un seul gestionnaire d’événements, dans le parent UserControl, qui effectue des tâches que seul le contrôle parent peut faire (c’est-à-dire, appelant de manière conditionnelle un événement, tel que défini dans le parent). Je reliais ensuite ce gestionnaire d'événements à toutes mes zones d'entrée dans mes contrôles enfants, et les contrôles enfants triaient la tâche qui consistait à analyser l'entrée et à dire au contrôle parent si cet événement devait être généré. Bon et propre, pas de code copier-coller répétitif (ce qui pour moi toujours résulte en un bogue).

Voici ma question. Visual Studio pense que je suis trop malin et m'avertit que "la méthode 'CheckReadiness' [le gestionnaire d'événements dans le parent] ne peut pas être la méthode d'un événement car une classe dont cette classe dérive définit déjà la méthode. " Oui, Visual Studio, c'est ce qui compte . Je veux disposer d'un gestionnaire d'événements qui ne gère que les événements générés par les classes enfant. Son seul travail est de me permettre de connecter les enfants sans avoir à écrire une seule ligne de code. Je n'ai pas besoin de ces gestionnaires supplémentaires: toutes les fonctionnalités dont j'ai besoin s'appellent naturellement lorsque les enfants traitent l'entrée utilisateur.

Je ne sais pas pourquoi Visual Studio a commencé à se plaindre à ce sujet maintenant (car cela me permettait de le faire auparavant), et je ne sais pas comment le faire disparaître. De préférence, j'aimerais le faire sans avoir à définir une méthode qui appelle simplement CheckReadiness. Qu'est-ce qui cause cet avertissement? Qu'est-ce qui le fait apparaître maintenant qu'il ne l'était pas il y a une heure, et comment puis-je le faire disparaître sans avoir recours à la fabrication de petits manieurs dans toutes les classes?

Était-ce utile?

La solution

Déclarez la méthode parent virtuelle, remplacez-la dans les classes enfants et appelez

base.checkReadyness(sender, e);

(ou la dérive de celle-ci) de la classe enfant. Cela permet une évolution future de la conception, par exemple, si vous souhaitez utiliser un code de vérification d’erreur spécifique avant d’appeler le gestionnaire d’événements parent. Vous n'aurez peut-être pas besoin d'écrire des millions de gestionnaires d'événements comme celui-ci pour chaque contrôle; vous pouvez simplement en écrire un, relier tous les contrôles à ce gestionnaire d'événements qui appelle à son tour le gestionnaire d'événements du parent.

Une chose que j'ai notée, c'est que si tout ce code est placé dans une dll, vous risquez de rencontrer un problème de performance lorsque vous essayez d'appeler un gestionnaire d'événements à partir d'une dll.

Autres conseils

Je viens de découvrir celui-ci également, je conviens que vous avez l'impression de tout faire correctement. Déclarer la méthode virtuelle est au mieux une solution de contournement, pas une solution.

Ce qui est fait est valide - un contrôle qui n'existe que dans la classe dérivée, et la classe dérivée attache un gestionnaire d'événements à l'un des événements de ce contrôle. Le fait que la méthode qui gère l'événement soit définie dans la classe de base n'est ni ici ni là-bas, elle est disponible au point de liaison à l'événement. L’événement n’est pas lié à deux fois ou à quelque chose d'aussi idiot, c'est simplement une question de l'endroit où la méthode qui gère l'événement est définie.

Très certainement, ce n'est pas une méthode virtuelle. Je ne veux pas que la méthode puisse être remplacée par une classe dérivée. Très frustrant, et à mon avis, un bug dans dev-studio.

J'ai moi aussi rencontré ce problème car, dans les versions précédentes de VS, vous pouviez "hériter". les gestionnaires d'événements. Donc, la solution que j'ai trouvée sans avoir à redéfinir les méthodes consiste simplement à affecter le gestionnaire d'événements quelque part dans la phase d'initialisation du formulaire. Dans mon cas, effectué dans le constructeur (je suis sûr que OnLoad () fonctionnerait aussi):

    public MyForm()
    {
        InitializeComponent();
        btnOK.Click += Ok_Click;
    }

... où le gestionnaire Ok_Click réside dans le formulaire de base. Matière à réflexion.

Je viens tout juste de rencontrer le problème exact que Merus a soulevé pour la première fois et, comme les autres qui ont posté des réponses, je ne comprends pas du tout pourquoi VS (qui utilise maintenant Visual C # 2010 Express) s'oppose à ce que le gestionnaire d'événements soit défini. dans la classe de base. La raison pour laquelle je poste une réponse est que, dans le processus de résolution du problème en faisant du code de classe de base une méthode protégée que les classes dérivées invoquent simplement dans leurs gestionnaires d’événements (essentiellement vides), j’ai renommé le refactor de la base. méthode de classe et a remarqué que le concepteur de VS a cessé de se plaindre. En d’autres termes, il a renommé l’enregistrement du gestionnaire d’événements (il n’a donc plus suivi la convention du concepteur VS consistant à nommer les gestionnaires d’événements avec ControlName_EventName), ce qui a semblé le satisfaire. Lorsque j'ai ensuite essayé d'inscrire le gestionnaire d'événements de base (maintenant renommé) contre les contrôles de classe dérivés en entrant le nom dans l'événement VS approprié, le concepteur a créé un nouveau gestionnaire d'événements dans la classe dérivée que j'ai ensuite supprimée, en laissant le contrôle de classe dérivé enregistré. à la méthode de la classe de base (gestionnaire d'événements). Net, comme vous vous en doutez, C # trouve ce que nous voulons faire de manière légitime. Seul le concepteur de VS qui ne l'aime pas lorsque vous suivez la convention de dénomination du gestionnaire d'événement du concepteur. Je ne vois pas la nécessité pour le designer de travailler de cette façon. N'importe qui, le temps de continuer.

Si votre événement est déjà défini dans votre classe parent, vous n'avez pas besoin de le recâbler dans votre classe enfant. Cela fera que l'événement se déclenche deux fois.

Vérifiez si c'est ce qui se passe. HTH:)

Cet article sur MSDN devrait constituer un bon point de départ: Remplacement des gestionnaires d’événements avec Visual Basic .NET . Examinez la section Comment la clause Handles peut causer des problèmes dans la classe dérivée .

Pourquoi ne pas déclarer la méthode virtuelle dans la classe parent, puis la remplacer dans les classes dérivées pour ajouter des fonctionnalités supplémentaires?

Oubliez que c'est un gestionnaire d'événement et faites juste un remplacement de méthode régulière approprié dans la classe enfant

Voici ce que j'ai fait pour que les méthodes de base soient appelées sous plusieurs formes similaires, chacune d'entre elles présentant quelques fonctionnalités supplémentaires par rapport aux plus courantes:

        protected override void OnLoad(EventArgs e)
    {
        try
        {
            this.SuspendLayout();
            base.OnLoad(e);

            foreach (Control ctrl in Controls)
            {
                Button btn = ctrl as Button;
                if (btn == null) continue;

                if (string.Equals(btn.Name, "btnAdd", StringComparison.Ordinal))
                    btn.Click += new EventHandler(btnAdd_Click);
                else if (string.Equals(btn.Name, "btnEdit", StringComparison.Ordinal))
                    btn.Click += new EventHandler(btnEdit_Click);
                else if (string.Equals(btn.Name, "btnDelete", StringComparison.Ordinal))
                    btn.Click += new EventHandler(btnDelete_Click);
                else if (string.Equals(btn.Name, "btnPrint", StringComparison.Ordinal))
                    btn.Click += new EventHandler(btnPrint_Click);
                else if (string.Equals(btn.Name, "btnExport", StringComparison.Ordinal))
                    btn.Click += new EventHandler(btnExport_Click);
            }

Le risque de ne pas utiliser le nom correct du bouton fixe me ressemble, de même que le risque de ne pas câbler manuellement le gestionnaire hérité.

Notez que vous devrez peut-être tester ceci.DesignMode pour ignorer le code dans VS Designer, mais cela fonctionne correctement pour moi même sans vérification.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top