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 :

Explications sur le pattern MVP


Sujet :

C#

  1. #1
    Rédacteur
    Avatar de Arnaud F.
    Homme Profil pro
    Développeur COBOL
    Inscrit en
    août 2005
    Messages
    5 183
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France

    Informations professionnelles :
    Activité : Développeur COBOL
    Secteur : Finance

    Informations forums :
    Inscription : août 2005
    Messages : 5 183
    Points : 8 870
    Points
    8 870
    Par défaut Explications sur le pattern MVP
    Bonjour,

    dans un avenir proche, je dois développer plusieurs applications (en WinForms dans un premier temps et WPF dans un second).

    Pour mes applications WinForms, je souhaite donc utilisé le pattern MVP pour une raison très simple, c'est plusieurs UI qui utilisent le même code métier.

    Dans un premier temps, je suis sur l'application de chargement (un bête Splash Screen).

    J'ai parcouru quelques articles sur le net mais tout ça me paraît encore bien mystérieux.

    Les comportements que je souhaite définir pour l'UI du splash screen :
    • se ferme automatiquement en cas de réussite ;
    • ne se ferme pas en cas d'erreur ;
    • affiche l'état d'avancement ainsi que divers messages.


    J'ai donc mon code métier :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    // Throws *Exception
    public static class Business
    {
        public static void Update() { /* ... */ }
    }
    Mon interface à implémenter pour chaque splash screen
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    public interface ISplashScreenView
    {
        void UpdateView();
    }
    Ma classe Presenter :

    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
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    public class SplashScreenPresenter
    {
            private ISplashScreenView _view;
     
            public SplashScreenPresenter(ISplashScreenView view)
            {
                _view = view;
     
                // Lancement de la mise à jour
                try
                {
                    CanClose = false;
                    Business.Update();
                }
                catch(Exception ex)
                {
                    ErrorMessage = ex.Message;
                }
                finally
                {
                    CanClose = true;
                }
            }
     
            public string CanClose 
            { get; internal set; }
     
            public string ErrorMessage 
            { get; internal set; }
     
            public string Message 
            { get; internal set; }
     
            public int Percentage
            { get; internal set; }
    }
    Une des UI :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    public partial class SplashScreen : Form, ISplashScreenView
    {
            private void SplashScreen_Load(object sender, EventArgs e)
            {
                new SplashScreenPresenter(this);
            }
     
            public void UpdateView() { /* ... */ }
    }
    Mais là je sèche, en effet, c'est mon code Business qui détient les messages à affecter et le taux d'avancement, ce qui impliquerait que je passe ma classe Presenter à ma classe Business...

    C'est bien comme ça qu'il faut procéder? Y a-t-il des failles dans mon système (sûrement )?

    Comment implémenter la gestion des events? (Dire à l'UI de quitter ou non), ...

    Le Presenter doit-il implémenter INotifyPropertyChanged?

    C'est par l'adresse que vaut le bûcheron, bien plus que par la force. Homère

    Installation de Code::Blocks sous Debian à partir de Nightly Builds

  2. #2
    Membre émérite Avatar de Guulh
    Homme Profil pro
    Inscrit en
    septembre 2007
    Messages
    2 160
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : septembre 2007
    Messages : 2 160
    Points : 2 924
    Points
    2 924
    Par défaut
    Ah, le MVP J'avais bien aimé cette note de blog : http://www.ctrl-shift-b.com/2008/11/...senter-styles/ qui montre bien qu'il y a plein de façons différentes de faire, en allant à l'extrême au MVVM.

    Ce qui est fixe, en tous cas, c'est que la vue ne contient, dans la mesure du possible, que du code trivial, c'est à dire qu'elle n'expose que des propriétés publiques (du style public string Login { get { return tbLogin.Text; } }), des appels au presenter suite à l'action de l'user (du style btnClick(object s, EventArgs e) { _presenter.AuBoulot(); }), ...

    Ce qui dépend du goût de chacun, ensuite, c'est la nature du lien vue / presenter.
    • La vue lève des events quand telle ou telle action se produit, et elle peut ne pas avoir besoin du presenter (cf l'article)
    • La vue référence le presenter, et appelle directement certaines de ses méthodes
    • La vue se binde aux propriétés du presenter, dans les limites du moteur de binding utilisé
    Je préfère la seconde solution, perso, qui facilite l'écriture de tests unitaires du presenter.

    Mais là, tel que tu le fais, si ton IView n'a qu'une méthode UpdateView, ça laisse supposer que c'est la vue elle même qui va lire des propriétés du presenter pour se mettre à jour elle-même. Pas good

    Non ta vue devrait plutôt ressembler à ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    interface ISplashScreenView
    {
       void AddMessage(string msg);
       void ReportProgress(int percent);
       void Close();
    }
    Pour ce qui est de INotifyPropertyChanged : bah ça dépend comme tu fais ton binding. En effet, tu peux par exemple avoir le presenter qui a lui-même des propriétés auxquelles la vue s'abonnera, et là pour que le binding se mette à jour, il faut effectivement implémenter cette interface.
    ಠ_ಠ

  3. #3
    Rédacteur
    Avatar de Arnaud F.
    Homme Profil pro
    Développeur COBOL
    Inscrit en
    août 2005
    Messages
    5 183
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France

    Informations professionnelles :
    Activité : Développeur COBOL
    Secteur : Finance

    Informations forums :
    Inscription : août 2005
    Messages : 5 183
    Points : 8 870
    Points
    8 870
    Par défaut
    Citation Envoyé par Guulh Voir le message
    Ah, le MVP J'avais bien aimé cette note de blog : http://www.ctrl-shift-b.com/2008/11/...senter-styles/ qui montre bien qu'il y a plein de façons différentes de faire, en allant à l'extrême au MVVM.
    Je n'étais jamais tombé sur cet article, je vais donc prendre le temps de le lire. (L'anglais ne me dérangeant pas )

    Citation Envoyé par Guulh Voir le message
    Ce qui est fixe, en tous cas, c'est que la vue ne contient, dans la mesure du possible, que du code trivial, c'est à dire qu'elle n'expose que des propriétés publiques (du style public string Login { get { return tbLogin.Text; } }), des appels au presenter suite à l'action de l'user (du style btnClick(object s, EventArgs e) { _presenter.AuBoulot(); }), ...
    Je suis tout à fait d'accord, d'où l'utilité de ce pattern, car pour ce même Splash Screen je suis amené à le faire pour différents framework (Compact (CE / Mobile) & NET Framework ...)

    Citation Envoyé par Guulh Voir le message
    Ce qui dépend du goût de chacun, ensuite, c'est la nature du lien vue / presenter.
    • La vue lève des events quand telle ou telle action se produit, et elle peut ne pas avoir besoin du presenter (cf l'article)
    • La vue référence le presenter, et appelle directement certaines de ses méthodes
    • La vue se binde aux propriétés du presenter, dans les limites du moteur de binding utilisé
    Je préfère la seconde solution, perso, qui facilite l'écriture de tests unitaires du presenter.
    Je penche aussi pour le second pour la même raison à savoir que dans mon cas, nous effectuerons toujours des tests unitaires sur le business avant même de tester l'UI (secondaire).

    Citation Envoyé par Guulh Voir le message
    Mais là, tel que tu le fais, si ton IView n'a qu'une méthode UpdateView, ça laisse supposer que c'est la vue elle même qui va lire des propriétés du presenter pour se mettre à jour elle-même. Pas good
    C'est comme ça que je voyais la chose justement à savoir que la vue se met à jour en lisant les données du presenter, en quoi c'est choquant? Dans tous les cas la vue devra se mettre elle-même à jour, non? (cf dernière remarque)

    Citation Envoyé par Guulh Voir le message
    Non ta vue devrait plutôt ressembler à ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    interface ISplashScreenView
    {
       void AddMessage(string msg);
       void ReportProgress(int percent);
       void Close();
    }
    Soit

    Citation Envoyé par Guulh Voir le message
    Pour ce qui est de INotifyPropertyChanged : bah ça dépend comme tu fais ton binding. En effet, tu peux par exemple avoir le presenter qui a lui-même des propriétés auxquelles la vue s'abonnera, et là pour que le binding se mette à jour, il faut effectivement implémenter cette interface.
    Justement, plus haut, tu disais que c'était "Pas good" ( ) de réaliser de la sorte, à savoir que la vue s'abonne au propriétés du presenter. Et donc ... ?

    Une question reste en suspend : comment faire pour que mon code métier puisse mettre à jour les messages du Presenter !?

    m'sieur
    C'est par l'adresse que vaut le bûcheron, bien plus que par la force. Homère

    Installation de Code::Blocks sous Debian à partir de Nightly Builds

  4. #4
    Membre émérite Avatar de Guulh
    Homme Profil pro
    Inscrit en
    septembre 2007
    Messages
    2 160
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : septembre 2007
    Messages : 2 160
    Points : 2 924
    Points
    2 924
    Par défaut
    Citation Envoyé par Arnaud F. Voir le message
    Je penche aussi pour le second pour la même raison à savoir que dans mon cas, nous effectuerons toujours des tests unitaires sur le business avant même de tester l'UI (secondaire).
    Oui, mais le presenter a quand même de la logique qui est testable. Par exemple, s'assurer qu'on affiche un message à l'user quand un champ login est vide, que la vue est bien mise à jour quand telle méthode est appelée, etc.


    Citation Envoyé par Arnaud F. Voir le message
    C'est comme ça que je voyais la chose justement à savoir que la vue se met à jour en lisant les données du presenter, en quoi c'est choquant? Dans tous les cas la vue devra se mettre elle-même à jour, non? (cf dernière remarque)
    Si elle ne se met à jour que via binding, pas de souci. Si on fait confiance au moteur de binding, y'a pas de place pour un bug. Par contre, une méthode du style (au pif)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    if (Today = Mardi)
       this.BackColor = Color.Blue;
    // ou bien
    if (this.Presenter.Model.DownloadFinished)
      this.tbMessage.Text += ""ayé, j'ai fini !"
    (c'est à dire du binding manuel) a sa place dans le presenter, la vue se contentant de wrapper BackColor et tbMessage dans des propriétés / des méthodes.

    Une question reste en suspend : comment faire pour que mon code métier puisse mettre à jour les messages du Presenter !?
    Ben disons que ton modèle a cette tête :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    class Modele
    {
       public void CommencerTraitementTrèsTrèsLong() { ... }
       public event MachinEventHandler Tonevent;
    }
    Le presenter, à un moment, lance le traitement du modèle; il est abonné à l'event, et l'event contient notamment un message à afficher. La tâche du Presenter se limite ici, dans la méthode abonnée à l'event, d'appeler la méthode qui va bien de la vue (AddNewMessage, par exemple), et la vue, fait e qu'elle veut du message (le mettre dans une ListBox, la prononcer à haute voix traduite en klingon, ...)

    Par ailleurs, il est préférable d'éviter que ta classe Business soit statique, sinon tes presenters ne seront pas testables.


    Je résume: la mise à jour de la vue fait partie des choses que l'on veut rendre testable. Ca peut se faire soit en mettant la logique de MAJ dans le presenter (qui est là pour ça), soit en rendant cette MAJ triviale par l'usage de binding (le test se limitant alors à tester la valeur de telle ou telle propriété du presenter).
    ಠ_ಠ

  5. #5
    Rédacteur
    Avatar de Arnaud F.
    Homme Profil pro
    Développeur COBOL
    Inscrit en
    août 2005
    Messages
    5 183
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France

    Informations professionnelles :
    Activité : Développeur COBOL
    Secteur : Finance

    Informations forums :
    Inscription : août 2005
    Messages : 5 183
    Points : 8 870
    Points
    8 870
    Par défaut
    Citation Envoyé par Guulh Voir le message
    Oui, mais le presenter a quand même de la logique qui est testable. Par exemple, s'assurer qu'on affiche un message à l'user quand un champ login est vide, que la vue est bien mise à jour quand telle méthode est appelée, etc.
    Oui tout à fait, les TU c'est aussi pour le Presenter, désolé de pas l'avoir écrit


    Citation Envoyé par Guulh Voir le message
    Si elle ne se met à jour que via binding, pas de souci. Si on fait confiance au moteur de binding, y'a pas de place pour un bug. Par contre, une méthode du style (au pif) [...] (c'est à dire du binding manuel) a sa place dans le presenter, la vue se contentant de wrapper BackColor et tbMessage dans des propriétés / des méthodes.
    Je suis d'accord. Mon but étant quand même de limiter la vue au maximum, beaucoup de choses seront dans le Presenter et la mise à disposition des messages étant déjà dans le Presenter, la vue n'aura qu'a récupérer les messages en question.

    Je souhaite (pour le splash screen tout du moins) limiter au maximum la liaison Presenter -> Vue (un simple pattern Observable au final).

    Citation Envoyé par Guulh Voir le message
    Ben disons que ton modèle a cette tête :
    [ ... ]
    Le presenter, à un moment, lance le traitement du modèle; il est abonné à l'event, et l'event contient notamment un message à afficher. La tâche du Presenter se limite ici, dans la méthode abonnée à l'event, d'appeler la méthode qui va bien de la vue (AddNewMessage, par exemple), et la vue, fait e qu'elle veut du message (le mettre dans une ListBox, la prononcer à haute voix traduite en klingon, ...)
    Ok, le Presenter n'est qu'un relai au final

    Citation Envoyé par Guulh Voir le message
    Par ailleurs, il est préférable d'éviter que ta classe Business soit statique, sinon tes presenters ne seront pas testables.
    Ah bon, pourquoi !?

    Citation Envoyé par Guulh Voir le message
    Je résume: la mise à jour de la vue fait partie des choses que l'on veut rendre testable. Ca peut se faire soit en mettant la logique de MAJ dans le presenter (qui est là pour ça), soit en rendant cette MAJ triviale par l'usage de binding (le test se limitant alors à tester la valeur de telle ou telle propriété du presenter).
    C'est par l'adresse que vaut le bûcheron, bien plus que par la force. Homère

    Installation de Code::Blocks sous Debian à partir de Nightly Builds

  6. #6
    Membre émérite Avatar de Guulh
    Homme Profil pro
    Inscrit en
    septembre 2007
    Messages
    2 160
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : septembre 2007
    Messages : 2 160
    Points : 2 924
    Points
    2 924
    Par défaut
    Citation Envoyé par Arnaud F. Voir le message
    Je souhaite (pour le splash screen tout du moins) limiter au maximum la liaison Presenter -> Vue (un simple pattern Observable au final).
    Tu veux que qui observe qui ? Si tu fais du binding, alors la vue observera le presenter, mais ça sera automatique. Sinon, ça veut dire que la vue aura l'intelligence de savoir quoi faire des événements émis par le presenter, alors qu'on veut précisément qu'elle soit la plus stupide possible. Et dans l'autre sens, a priori les seuls events que la vue peut émettre sont liées à l'activité de l'utilisateur, et comme on a vu tout à l'heure on a le choix entre (1) la vue appelle alors des méthodes du presenter ou (2) elle émet un event, et charge au presenter de s'y abonner. C'est juste une question de goût. Comme je disais, je préfère la deuxième solution pour faciliter les tests, mais aussi parce que je trouve que ce'st de l'overkill d'utiliser les events alors qu'on a qu'un abonné, bien connu de surcroît.
    Citation Envoyé par Arnaud F. Voir le message
    Ah bon, pourquoi !?
    Pourquoi pas statique ? Ben parce que tu pourras pas le mocker. Ton presenter aura forcément un lien explicite vers ta classe business (pas le choix, ses méthodes sont statiques), et tu pourras pas isoler les méthodes qui font appel au Business.

    Accessoirement, en relisant ton post initial : il n'est pas nécessaire de faire du MVP ou du MVC pour avoir du code réutilisable. Si l'appli est déjà correctement séparée en couches, plusieurs UI pourront attaquer le même code métier. Après, là où tu peux gagner avec le MVP, c'est si tes différentes UI partagent beaucoup de logique de présentation, auquel cas tu peux espérer réutiliser aussi les Presenters. et ça facilitera aussi une migration vers WPF
    ಠ_ಠ

  7. #7
    Rédacteur
    Avatar de Arnaud F.
    Homme Profil pro
    Développeur COBOL
    Inscrit en
    août 2005
    Messages
    5 183
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France

    Informations professionnelles :
    Activité : Développeur COBOL
    Secteur : Finance

    Informations forums :
    Inscription : août 2005
    Messages : 5 183
    Points : 8 870
    Points
    8 870
    Par défaut
    J'aime les débats constructifs

    Citation Envoyé par Guulh Voir le message
    Tu veux que qui observe qui ? Si tu fais du binding, alors la vue observera le presenter, mais ça sera automatique. Sinon, ça veut dire que la vue aura l'intelligence de savoir quoi faire des événements émis par le presenter, alors qu'on veut précisément qu'elle soit la plus stupide possible. Et dans l'autre sens, a priori les seuls events que la vue peut émettre sont liées à l'activité de l'utilisateur, et comme on a vu tout à l'heure on a le choix entre (1) la vue appelle alors des méthodes du presenter ou (2) elle émet un event, et charge au presenter de s'y abonner. C'est juste une question de goût.
    Je parle de la vue qui observe le presenter et non dans l'autre sens (étant donné que ça n'est qu'un bête écran de chargement, la vue n'a aucunement besoin de piloter le presenter! Juste de savoir l'état courant du chargement).

    Juste pour qu'on soit bien d'accord, quand on parle de "binding", on parle bien de :

    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
    public class SplashScreenView : Form, ISplashScreenView
    {
            private SplashScreenPresenter _presenter;
     
            private void SplashScreen_Load(object sender, EventArgs e)
            {
                    _presenter = new SplashScreenPresenter(this);
                    // Supposons un event Success
                    _presenter.Success += new EventHandler(OnSuccess);
            }
     
            public void UpdateView()
            {
                    this.MessageLabel = _presenter.Message;
                    this.DetailedMessageLabel = _presenter.DetailedMessage;
            }
     
            private void OnSuccess()
            {
                    MessageBox.Show("Success!");
            }
    }
    Et quand on parle de la stupidité de la vue, là c'est un bel exemple, je ne fais rien de plus.

    Citation Envoyé par Guulh Voir le message
    Comme je disais, je préfère la deuxième solution pour faciliter les tests, mais aussi parce que je trouve que ce'st de l'overkill d'utiliser les events alors qu'on a qu'un abonné, bien connu de surcroît.
    Dans le cas des tests (fonctionnels avec Fitnesse), je n'aurais pas forcément d'abonné dans le sens ou les tests fonctionnels n'utilisent pas d'UI. Donc, pour ma part, utiliser les méthodes du presenter me paraît plus accessible (et évite dans le cas des tests, d'avoir à les "simuler".

    Citation Envoyé par Guulh Voir le message
    Pourquoi pas statique ? Ben parce que tu pourras pas le mocker. Ton presenter aura forcément un lien explicite vers ta classe business (pas le choix, ses méthodes sont statiques), et tu pourras pas isoler les méthodes qui font appel au Business.
    Je me suis pas encore penché sur les mocks, j'en ai entendu parler, je sais ce que c'est, mais jamais utilisé, donc dit comme ça, je comprend mieux le pourquoi du comment .

    Citation Envoyé par Guulh Voir le message
    Accessoirement, en relisant ton post initial : il n'est pas nécessaire de faire du MVP ou du MVC pour avoir du code réutilisable. Si l'appli est déjà correctement séparée en couches, plusieurs UI pourront attaquer le même code métier. Après, là où tu peux gagner avec le MVP, c'est si tes différentes UI partagent beaucoup de logique de présentation, auquel cas tu peux espérer réutiliser aussi les Presenters. et ça facilitera aussi une migration vers WPF
    En fait, comme je l'ai dis dans un post précédent, la logique UI sera strictement identique entre les différentes vues ! C'est juste que développant une appli multi framework & devices, je voulais bien séparé le tout pour justement gagné en évolutivité et migration (de l'UI).

    Ce qui me manque dans l'exemple que j'ai donné (ou qui est faux tout du moins) c'est la partie modèle qui elle :
    • ne doit pas être static
    • doit implémenter une interface de sorte que le presenter puisse recevoir les notifications du modele et le piloter au besoin.


    Ca me plaît bien tout ça

    P.S: 2j pour comprendre la logique du MVP, alors qu'en fait c'est accessible et surtout du bon sens...
    C'est par l'adresse que vaut le bûcheron, bien plus que par la force. Homère

    Installation de Code::Blocks sous Debian à partir de Nightly Builds

  8. #8
    Membre émérite Avatar de Guulh
    Homme Profil pro
    Inscrit en
    septembre 2007
    Messages
    2 160
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : septembre 2007
    Messages : 2 160
    Points : 2 924
    Points
    2 924
    Par défaut
    Citation Envoyé par Arnaud F. Voir le message
    Juste pour qu'on soit bien d'accord, quand on parle de "binding", on parle bien de (sniiip du code):
    C'est du binding manuel, ça. Windows Forms propose la classe Binding, utilisée comme suit :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    this.textBoxTruc.DataBindings.Add(new Binding("Text", this.Presenter, "ClientName", true));
    Ca fait partie de choses que le designer de winforms met en avant, et qui font que tu peux concevoir une bonne part d'une appli business classique (avec une grille qui chope des données d'un DB, par ex) rien qu'avec le designer, sans toucher au code.

    Je vais pas te faire un cours sur la classe Binding, mais en gros ça synchronise une propriété graphique à une une propriété métier, avec une politique paramétrable de read / write entre UI et métier (dès modification, programmatiquement, ou à validation ; on peut aussi spécifier un formatage.)

    Pour ton "Success" : perso, je considère qu'afficher un message à l'user n'est pas du ressort de la vue. Déjà parce que ça peut se faire au milieu d'un workflow (du style connecté ? oui => download ; non => demander confirmation à l'user ; si oui connection, sinon arrêt ; si ... tu vois le truc)
    et donc j'ai une classe qui wrappe les messagebox, à laquelle les presenter ont accès.

    Non, vraiment, la vue ne doit RIEN faire, à part wrapper son état, et faire du binding déclaratif. En WPF MVVM, elle ne contient aucun code, étant écrite en XAML. Par contre, elle configure déclarativement pas mal d'objets (commandes, bindings, ...)
    Et quand on parle de la stupidité de la vue, là c'est un bel exemple, je ne fais rien de plus.
    C'est déjà trop
    la partie modèle ne doit pas être static
    Ca ne remet pas en cause la réutisabilité de ton code, mais sa testabilité.

    la partie modèle doit implémenter une interface de sorte que le presenter puisse recevoir les notifications du modele et le piloter au besoin.
    Euh, non Faire du modèle une classe implémentant une interface, elle-même étant tout ce que le presenter connait, ca permet juste de limiter le couplage entre tes couches, avec tous les avantages associés (testabilité comme on a vu, mais aussi possibilité d'utiliser de l'injection de dépendances par exemple)
    ಠ_ಠ

  9. #9
    Rédacteur
    Avatar de Arnaud F.
    Homme Profil pro
    Développeur COBOL
    Inscrit en
    août 2005
    Messages
    5 183
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France

    Informations professionnelles :
    Activité : Développeur COBOL
    Secteur : Finance

    Informations forums :
    Inscription : août 2005
    Messages : 5 183
    Points : 8 870
    Points
    8 870
    Par défaut
    Citation Envoyé par Guulh Voir le message
    C'est du binding manuel, ça. Windows Forms propose la classe Binding, utilisée comme suit :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    this.textBoxTruc.DataBindings.Add(new Binding("Text", this.Presenter, "ClientName", true));
    Ca fait partie de choses que le designer de winforms met en avant, et qui font que tu peux concevoir une bonne part d'une appli business classique (avec une grille qui chope des données d'un DB, par ex) rien qu'avec le designer, sans toucher au code.

    Je vais pas te faire un cours sur la classe Binding, mais en gros ça synchronise une propriété graphique à une une propriété métier, avec une politique paramétrable de read / write entre UI et métier (dès modification, programmatiquement, ou à validation ; on peut aussi spécifier un formatage.)
    Compris ! Tellement plus simple en effet.


    Citation Envoyé par Guulh Voir le message
    Pour ton "Success" : perso, je considère qu'afficher un message à l'user n'est pas du ressort de la vue. Déjà parce que ça peut se faire au milieu d'un workflow (du style connecté ? oui => download ; non => demander confirmation à l'user ; si oui connection, sinon arrêt ; si ... tu vois le truc)
    et donc j'ai une classe qui wrappe les messagebox, à laquelle les presenter ont accès.
    Si j'ai bien compris :
    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
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
     
    //
    public interface ISplashScreenView
    {
        bool AskRestart();
        bool AskContinue();
        void Success();
        void Error(Exception ex);
    }
     
    // Presenter's workflow
    public void DoJob
    {
        [ ... ]
        if(AskContinue())
        { [ ... ] }
        else
        { AskRestart(); [ ... ] }
     
        Success();
    }
     
    // View
    public bool AskContinue()
    {
        return DialogResult.Yes == MessageBox.Show("Continue ?", "", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2);
    }
     
    public bool AskRestart()
    {
        return DialogResult.Yes == MessageBox.Show("Restart ?", "", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2);
    }
     
    public void Success()
    {
        MessageBox.Show("Youhou !");
    }
    Citation Envoyé par Guulh Voir le message
    Non, vraiment, la vue ne doit RIEN faire, à part wrapper son état, et faire du binding déclaratif. En WPF MVVM, elle ne contient aucun code, étant écrite en XAML. Par contre, elle configure déclarativement pas mal d'objets (commandes, bindings, ...)
    J'ai cru voir ça pour le MVVM

    Citation Envoyé par Guulh Voir le message
    C'est déjà trop
    Ca ne remet pas en cause la réutisabilité de ton code, mais sa testabilité.
    C'est hallucinant comme on peut réduire le code au strict essentiel quand c'est bien foutu...

    Citation Envoyé par Guulh Voir le message
    Euh, non Faire du modèle une classe implémentant une interface, elle-même étant tout ce que le presenter connait, ca permet juste de limiter le couplage entre tes couches, avec tous les avantages associés (testabilité comme on a vu, mais aussi possibilité d'utiliser de l'injection de dépendances par exemple)
    Compris !

    Mais en mode <mettre l'adjectif qui convient>, si je veux que mon modèle génère des messages (sur l'état d'avancement par exemple) et veux les afficher dans ma vue, il faut bien que le presenter les récupère. A moins qu'ici aussi je peux faire du DataBinding?
    C'est par l'adresse que vaut le bûcheron, bien plus que par la force. Homère

    Installation de Code::Blocks sous Debian à partir de Nightly Builds

  10. #10
    Membre émérite Avatar de Guulh
    Homme Profil pro
    Inscrit en
    septembre 2007
    Messages
    2 160
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : septembre 2007
    Messages : 2 160
    Points : 2 924
    Points
    2 924
    Par défaut
    Citation Envoyé par Arnaud F. Voir le message
    Si j'ai bien compris
    Yep, en tous cas c'est comme ça que je fais.
    Accessoirement, dans le cas précis des MessageBox qui ont des tas de paramètres (icones, titre, boutons, ...), n'avoir que 3 ou 4 méthodes (du style Ask, AskWarning, ShowInfo, ShowWarning, ShowError, ...) permet de standardiser un peu (et d'éviter qu'un coup on oublie telle icone, qu'un coup on met tel titre et pas tel autre dans deux contextes très proches, ...)
    C'est hallucinant comme on peut réduire le code au strict essentiel quand c'est bien foutu...
    Le binding, c'est vieux comme Hérode dans les langages plus ou moins RAD (style VB), y'a pas de lien direct avec MVP, même si MVP en profite bien en limitant le code de synchro dans les cas les plus triviaux.
    Mais en mode <mettre l'adjectif qui convient>, si je veux que mon modèle génère des messages (sur l'état d'avancement par exemple) et veux les afficher dans ma vue, il faut bien que le presenter les récupère. A moins qu'ici aussi je peux faire du DataBinding?
    Dans ton cas, oui, si le Modèle lève des events, il faut bien que le presenter s'y abonne (même si dans ton cas précis de ReportProgress, il se contentera de mettre à jour la vue).
    Et le binding et une techno d'UI (suffit devoir dans quel namespace la classe se trouve ), il n'a pas trop sa place dans la communication presenter / modèle.
    ಠ_ಠ

  11. #11
    Rédacteur
    Avatar de Arnaud F.
    Homme Profil pro
    Développeur COBOL
    Inscrit en
    août 2005
    Messages
    5 183
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France

    Informations professionnelles :
    Activité : Développeur COBOL
    Secteur : Finance

    Informations forums :
    Inscription : août 2005
    Messages : 5 183
    Points : 8 870
    Points
    8 870
    Par défaut
    Citation Envoyé par Guulh Voir le message
    Yep, en tous cas c'est comme ça que je fais.
    Accessoirement, dans le cas précis des MessageBox qui ont des tas de paramètres (icones, titre, boutons, ...), n'avoir que 3 ou 4 méthodes (du style Ask, AskWarning, ShowInfo, ShowWarning, ShowError, ...) permet de standardiser un peu (et d'éviter qu'un coup on oublie telle icone, qu'un coup on met tel titre et pas tel autre dans deux contextes très proches, ...)
    Oui, là ça va.

    Citation Envoyé par Guulh Voir le message
    Le binding, c'est vieux comme Hérode dans les langages plus ou moins RAD (style VB), y'a pas de lien direct avec MVP, même si MVP en profite bien en limitant le code de synchro dans les cas les plus triviaux.
    Et moi je reprends le C# depuis peu et mon premier challenge est de faire une appli multi-FW, multi-langues, multi-devices

    Citation Envoyé par Guulh Voir le message
    Dans ton cas, oui, si le Modèle lève des events, il faut bien que le presenter s'y abonne (même si dans ton cas précis de ReportProgress, il se contentera de mettre à jour la vue).
    Et le binding et une techno d'UI (suffit devoir dans quel namespace la classe se trouve ), il n'a pas trop sa place dans la communication presenter / modèle.
    Oui en effet.


    Quid des fichiers de ressources dans tout ça? Vu mes UI seront similaires, faudra faire un fichier de resources par screen ou je peux me permettre de faire des copier/coller ou bien faire des liens?
    C'est par l'adresse que vaut le bûcheron, bien plus que par la force. Homère

    Installation de Code::Blocks sous Debian à partir de Nightly Builds

  12. #12
    Membre émérite Avatar de Guulh
    Homme Profil pro
    Inscrit en
    septembre 2007
    Messages
    2 160
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : septembre 2007
    Messages : 2 160
    Points : 2 924
    Points
    2 924
    Par défaut
    Citation Envoyé par Arnaud F. Voir le message
    Quid des fichiers de ressources dans tout ça? Vu mes UI seront similaires, faudra faire un fichier de resources par screen ou je peux me permettre de faire des copier/coller ou bien faire des liens?
    Je ne parlerai que de winforms, ne connaissant pas bien WPF,et sachant que c'est assez différent.

    En winforms, donc, les ressources directes de la form (du style labels, images, ...) sont directement dans la méthode InitializeComponents du fichier TaForm.Designer.cs, et ne sont donc pas partageables. Par contre, si la form est localisable, alors ces ressources sont dans un fichier resx dédié (un par langue, en plus du resx par défaut).
    Les autres textes, qui ne sont pas définis par designer (au hasard, les messages des messagebox) sont eux gérés comme bon nous semble ; on peut notamment les mettre dans un (ou plusieurs) fichiers de ressources resx, visual studio se chargeant automatiquement de fournir un accès typée via une classe auto-générée.

    Donc, de mon expérience perso : tout ce qui est texte "statique" (ce mot a trop de sens différents, mais faute de mieux ... ) est directement associé à la form, dans InitializeComponents() ou dans le resx, et me parait donc difficilement partageable entre plusieurs technos d'UI ; le reste n'est pas dépendant d'une techno en particulier, et à ce titre est bien sûr utilisable par toutes.
    ಠ_ಠ

  13. #13
    Rédacteur
    Avatar de Arnaud F.
    Homme Profil pro
    Développeur COBOL
    Inscrit en
    août 2005
    Messages
    5 183
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France

    Informations professionnelles :
    Activité : Développeur COBOL
    Secteur : Finance

    Informations forums :
    Inscription : août 2005
    Messages : 5 183
    Points : 8 870
    Points
    8 870
    Par défaut
    Comme je l'ai déjà dit plus haut, ça devra être multilangue (à savoir au minimum EN / FR mais peut être aussi IT / ES / PL / RU / CN (surement même)). Donc "rien" ne sera statique, tout sera localisable. C'est pour ça que je posais la question !

    Je me vois mal développer une appli en 3 résolutions (& FW) différents avec à chaque fois 7 langues (dans le meilleur des cas) à mettre à jour sans pouvoir réutiliser les fichiers de ressources, bonjour la maintenance
    C'est par l'adresse que vaut le bûcheron, bien plus que par la force. Homère

    Installation de Code::Blocks sous Debian à partir de Nightly Builds

  14. #14
    Membre émérite Avatar de Guulh
    Homme Profil pro
    Inscrit en
    septembre 2007
    Messages
    2 160
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : septembre 2007
    Messages : 2 160
    Points : 2 924
    Points
    2 924
    Par défaut
    Je savais bien que j'aurais pas dû utiliser le mot "statique"

    Non le distingo que je fais, en gros, c'est entre (par exemple pour le texte) les valeurs que tu saisis dans l'éditeur de forms, et qui comme je le disais seront bien dans un fichier resx par langue, et les ressources "libres", situées dans des resx que tu gères entièrement.

    Mais je ne sais pas s'il y aurait moyen de facilement isoler toutes les ressources dans un endroit donné, de façon à ce qu'elles soient aisément consommables par différents types d'UI. Par du binding peut-être ?
    ಠ_ಠ

  15. #15
    Rédacteur
    Avatar de Arnaud F.
    Homme Profil pro
    Développeur COBOL
    Inscrit en
    août 2005
    Messages
    5 183
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France

    Informations professionnelles :
    Activité : Développeur COBOL
    Secteur : Finance

    Informations forums :
    Inscription : août 2005
    Messages : 5 183
    Points : 8 870
    Points
    8 870
    Par défaut
    Citation Envoyé par Guulh Voir le message
    Je savais bien que j'aurais pas dû utiliser le mot "statique"
    S'pas grave

    Citation Envoyé par Guulh Voir le message
    Non le distingo que je fais, en gros, c'est entre (par exemple pour le texte) les valeurs que tu saisis dans l'éditeur de forms, et qui comme je le disais seront bien dans un fichier resx par langue, et les ressources "libres", situées dans des resx que tu gères entièrement.
    Oui j'avais compris

    Citation Envoyé par Guulh Voir le message
    Mais je ne sais pas s'il y aurait moyen de facilement isoler toutes les ressources dans un endroit donné, de façon à ce qu'elles soient aisément consommables par différents types d'UI. Par du binding peut-être ?
    J'y ai pensé après coup ! Tiens si on faisait du binding pour ça aussi? Ca serait pas mal
    C'est par l'adresse que vaut le bûcheron, bien plus que par la force. Homère

    Installation de Code::Blocks sous Debian à partir de Nightly Builds

Discussions similaires

  1. [Multimédia] Explication sur stream audio
    Par champion dans le forum Développement
    Réponses: 1
    Dernier message: 20/01/2005, 13h14
  2. Besoin d'explications sur float et l'élasticité !
    Par KneXtasY dans le forum Mise en page CSS
    Réponses: 2
    Dernier message: 14/01/2005, 16h15
  3. s.v.p :explication sur le ".h" et dll de l'opengl
    Par Asmod_D dans le forum OpenGL
    Réponses: 1
    Dernier message: 22/11/2004, 11h32
  4. Réponses: 28
    Dernier message: 18/08/2003, 12h54
  5. recherches des cours ou des explications sur les algorithmes
    Par Marcus2211 dans le forum Algorithmes et structures de données
    Réponses: 6
    Dernier message: 19/05/2002, 23h18

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