IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C# Discussion :

Association d'une action à un bouton


Sujet :

C#

  1. #1
    Membre actif Avatar de Chen norris
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2004
    Messages
    216
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2004
    Messages : 216
    Points : 248
    Points
    248
    Par défaut Association d'une action à un bouton
    Bonjour à tous,

    Je suis confronté à un problème de mécanisme de programmation assez particulier : je travaille au développement d'une application en C# et dans laquelle certains boutons graphiques doivent activer diverses fonctions. Les boutons à créer sont stockés dans un fichier de configuration que je lis au début de mon programme (fichier du style "nom de bouton -> action à lancer"). Ma question est de savoir dans quel type de structure stocker proprement les boutons, de manière à stocker les fonctions associées à lancer.

    Une première idée était de stocker une chaine contenant le nom de la fonction.
    Exemple :
    Classe "Bouton" :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    public class Bouton {
    	String actionAssociee;
    	public Bouton(String actionLancee) {
    		actionAssociee = actionLancee;
    	}
    Code principal :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    ...
    List<Bouton> listeDeBoutons;
    ...
    // ici, je lis mon fichier de config en
    // extrayant nom de bouton et action 
    // associée  et pour chaque bouton, je fais :
    listeDeBoutons.Add(new Bouton(nomDeBouton));
    ...
    if (boutonClique.actionAssociee.Equals("toto"))
    	toto();
    Le souci, c'est que ça n'est pas du tout générique puisque je suis obligé d'écrire en dur dans le code l'association entre le bouton "toto" et l'action lancée toto().

    En fouinant un peu sur le net, je suis tombé sur les delegate, concept que je ne connaissais pas jusqu'à présent. Si j'ai bien tout compris suite à mes lectures, je peux avoir quelque chose du style :

    Classe "Bouton" :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    public class Bouton {
    private delegate void action();
    	action actionAssociee;
    	public Bouton(String actionLancee) {
    		actionAssociee = new action(actionLancee);
    	}
    Code principal :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    ...
    listeDeBoutons.Add(new Bouton(nomDeBouton));
    ...
    boutonClique.actionAssociee();
    Sauf qu'apparemment, je ne peux pas donner de chaine de caractères en paramètre lors de l'instanciation de Bouton. J'obtiens une erreur "actionLancee est une variable mais est utilisée comme une méthode". Le truc, c'est que je ne veux surtout pas donner explicitement de nom de méthode (ça ne me ferait au final que ré-écrire en dur l'association bouton->méthode).

    Est-ce que vous auriez une idée de comment mettre en place un système qui me permette de gérer proprement tout ça ?

    Merci d'avance pour vos explications.
    Chen norris
    C/C++, C#, Java, PHP & SQL coder
    Web developer

  2. #2
    Inactif  
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Janvier 2007
    Messages
    6 604
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Janvier 2007
    Messages : 6 604
    Points : 13 314
    Points
    13 314
    Par défaut
    Tu as la possibilité d'utiliser la reflection pour récupérer la méthode à lancer (à condition bien sur d'avoir une association explicite - égalité de nom par exemple- entre l'action et la méthode utilisée).

    Voir l'espace de nom System.Reflection et en particulier la méthode GetMethod de la classe Type.

    Je ne réponds pas aux questions techniques par MP ! Le forum est là pour ça...


    Une réponse vous a aidé ? utiliser le bouton

    "L’ennui dans ce monde, c’est que les idiots sont sûrs d’eux et les gens sensés pleins de doutes". B. Russel

  3. #3
    Membre actif Avatar de Chen norris
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2004
    Messages
    216
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2004
    Messages : 216
    Points : 248
    Points
    248
    Par défaut
    Ouch… Complexe à comprendre mais alors très efficace comme concept. J'ai cherché de la doc sur le net par rapport à ce que tu me disais et je pense avoir trouvé mon bonheur. Je ne marque pas mon post résolu pour le moment : je reviendrai poster le détail de la solution.

    Merci beaucoup en tous cas pour ce coup de pouce.
    Chen norris
    C/C++, C#, Java, PHP & SQL coder
    Web developer

  4. #4
    Membre expérimenté Avatar de ctxnop
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juillet 2007
    Messages
    858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Morbihan (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2007
    Messages : 858
    Points : 1 732
    Points
    1 732
    Par défaut
    Attention tout de même avec la reflection, c'est un chouilla bourrin comme truc.
    Ca répond parfaitement à ton besoin mais tu dois prendre quelques précautions.
    En effet, si on imagine que tu code le truc de cette façon :
    Code csharp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
     
    public partial class MonFormulaire
        : Form
    {
        private void LireFichier(string Chemin)
        {
            // Ici tu instancie tes ActionBouton et tu utilise la reflection
            // pour convertir "MonAction1" en un handler vers la méthode MonAction1
        }
     
        // ....
     
        // Ici l'action est donc une méthode de MonFormulaire
        private void MonAction1()
        {
            // ....
        }
     
        // Ci-dessous une méthode qui n'est pas une action disponible
        // et qui sert à drop une base de donnée
        private void DropDatabase()
        {
            // ....
        }
     
    }

    Voila, tout ca fonctionnera parfaitement, mais si tu ne fais pas attention un utilisateur mal attentionné pourra mettre comme action "DropDatabase" ce qui serait une catastrophe.

    De la même manière, si tu code trop générique (histoire de permettre par exemple de passer un paramètre à l'action), un détournement pourrait être fait pour faire exécuter n'importe quoi à ton formulaire.

    Je te conseil l'utilisation d'une classe (surement static) contenant uniquement les méthodes d'action liables. Lors de l'exécution de l'action du passera en paramètre ce qu'il faut (peut être ton formulaire ?). La recherche par reflection devra ensuite être faite uniquement dans le périmètre de la classe en question, ainsi on ne pourra pas détourner le fonctionnement.

  5. #5
    Inactif  
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Janvier 2007
    Messages
    6 604
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Janvier 2007
    Messages : 6 604
    Points : 13 314
    Points
    13 314
    Par défaut
    Citation Envoyé par ctxnop Voir le message
    Voila, tout ca fonctionnera parfaitement, mais si tu ne fais pas attention un utilisateur mal attentionné pourra mettre comme action "DropDatabase" ce qui serait une catastrophe.
    Il peut par exemple aisément sécuriser la chose en ajoutant une classe attribut (vide, avec un nom du style "ValidCustomActionAttribute") comme attribut de méthode pour les méthodes susceptibles d'être appelée et contrôler la présence de cet attribut avant de valider l'association nom action - méthode.


    Exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
     
     
    class MyClass
    {
     
    [ValidCustomAction]
    private void MyActionMethod()
    {
    }
    private void checkMethods(Type myType)
    {
    MethodInfo methodInfo = myType.GetMethod("MyActionMethod", false);
    Attribute validationAttribute = methodInfo.GetCustomAttributes(typeof(ValidCustomActionAttribute), false);
    if (validationAttribute == null)
    {
    // Methode non autorisée
    }
    }
    }
     
    class ValidCustomActionAttribute : Attribute
    {
    }

    Je ne réponds pas aux questions techniques par MP ! Le forum est là pour ça...


    Une réponse vous a aidé ? utiliser le bouton

    "L’ennui dans ce monde, c’est que les idiots sont sûrs d’eux et les gens sensés pleins de doutes". B. Russel

  6. #6
    Membre expérimenté Avatar de ctxnop
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juillet 2007
    Messages
    858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Morbihan (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2007
    Messages : 858
    Points : 1 732
    Points
    1 732
    Par défaut
    Citation Envoyé par Bluedeep Voir le message
    Il peut par exemple sécuriser la chose en ajoutant une classe attribut (vide, avec un nom du style "ValidCustomActionAttribute") comme attribut de méthode pour les méthodes susceptibles d'être appelée et contrôler la présence de cet attribut avant de valider l'association nom action - méthode.
    Oui aussi, c'est une autre solution. Je voulais surtout attirer son attention sur le fait qu'une liaison directe engendre sensiblement le même type de problème que l'injection SQL : une utilisation détournée qui exécute du code non souhaité.

  7. #7
    Inactif  
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Janvier 2007
    Messages
    6 604
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Janvier 2007
    Messages : 6 604
    Points : 13 314
    Points
    13 314
    Par défaut
    Citation Envoyé par ctxnop Voir le message
    Oui aussi, c'est une autre solution. Je voulais surtout attirer son attention sur le fait qu'une liaison directe engendre sensiblement le même type de problème que l'injection SQL : une utilisation détournée qui exécute du code non souhaité.
    Je suis entièrement d'accord avec cela. Je suggérais juste un schéma un peu moins "bourrin" que la simple association "nom d'action dans un fichier - nom methode dans une classe".

    Je ne réponds pas aux questions techniques par MP ! Le forum est là pour ça...


    Une réponse vous a aidé ? utiliser le bouton

    "L’ennui dans ce monde, c’est que les idiots sont sûrs d’eux et les gens sensés pleins de doutes". B. Russel

  8. #8
    Membre chevronné
    Profil pro
    Inscrit en
    Février 2005
    Messages
    1 273
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2005
    Messages : 1 273
    Points : 2 202
    Points
    2 202
    Par défaut
    Il y a un outil qui est magique pour faire ça et qui s'appelle Spring.

    Tu utilises le conteneur pour créer tes listes de bouton dans du code, et l'association de l'événement au code.

    Ca t'évitera beaucoup de pbs.

  9. #9
    Membre actif Avatar de Chen norris
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2004
    Messages
    216
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2004
    Messages : 216
    Points : 248
    Points
    248
    Par défaut
    Héhé, ce sont en effet des questions qui reviennent souvent… dans le cadre d'applications où la sécurité est importante (BDD ou autre). Or ce n'est pas mon cas : je travaille au développement d'un modeleur 3D et je souhaite lier des actions à mes boutons. Si l'action liée se retrouve malencontreusement être du style deleteAllScene, alors ça supprimera toute la scène mais ça reste une action voulue : pas de souci de sécurité donc pour moi

    Pour associer mes actions, j'ai donc :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    private delegate void launchAction();
    ...
    public void registerAction(String actionName) {
    	List<ParameterInfo> parametersList = new List<ParameterInfo>();
    	MethodInfo methodLaunched = typeof(MyManager).GetMethod(actionName);
    	action = Delegate.CreateDelegate(typeof(launchAction), methodLaunched, false);
    	parameters = methodLaunched.GetParameters().ToList();
    	listOfActions.Add(actionName, new Pair(action, parameters));
    }
    et pour les lancer :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    public void LaunchAction(String action) {
    	Delegate methodDelegate = (System.Delegate)listOfActions[action].First;
    	List<ParameterInfo> parameters = new List<ParameterInfo>();
    	parameters = (List<ParameterInfo>)listOfActions[action].Second;
    	methodDelegate.DynamicInvoke(parameters.ToArray());
    }
    Tout fonctionne au poil, c'est exactement ce que je souhaitais obtenir.
    Merci pour toutes vos précisions.

    Pour en revenir à ce problème de sécurité, seul les méthodes publiques de MyManager sont visibles : à moi de ne rendre publiques que les méthodes accessibles
    Chen norris
    C/C++, C#, Java, PHP & SQL coder
    Web developer

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 8
    Dernier message: 30/08/2010, 16h02
  2. Associer une action à un bouton dans une JDialog
    Par moomba dans le forum Agents de placement/Fenêtres
    Réponses: 0
    Dernier message: 07/12/2008, 20h08
  3. Associer une action à un bouton
    Par reram dans le forum Interfaces Graphiques
    Réponses: 4
    Dernier message: 09/08/2008, 16h47
  4. Algorithme spécifier une action à un bouton
    Par KinF dans le forum Langages de programmation
    Réponses: 3
    Dernier message: 09/12/2004, 05h20

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo