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

Windows Presentation Foundation Discussion :

[MVVM] Mediator et refresh de l'UI


Sujet :

Windows Presentation Foundation

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    8
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 8
    Par défaut [MVVM] Mediator et refresh de l'UI
    Bonjour,

    Je teste en ce moment le pattern MVVM. J'ai donc une classe Messenger qui s'occupe de transférer des messages entre mes ViewModel.

    Voilà mon problème :
    Mon application à une vue principale qui contient les éléments suivants :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
        <Grid>
            <v:MasterView Grid.Column="0" Grid.Row="1" />
            <ContentControl Grid.Column="1" Grid.Row="1" Content="{Binding Path=CurrentViewModel}">
                <ContentControl.Resources>
                    <DataTemplate DataType="{x:Type vm:ZoneViewModel}">
                        <v:DetailZoneView />
                    </DataTemplate>
                </ContentControl.Resources>
            </ContentControl>
        </Grid>
    En gros, MasterView est un treeview et le ContentControl va recevoir la vue détail du noeud sélectionné.

    Mon ViewModel maitre (MasterViewModel, lié à ViewModel) maintient une collection de ViewModel enfants (le maitre correspond au treeview et les enfants correspondent aux nœuds du treeview). Je me suis basé sur le second exemple de Josh Smith dans cet article.
    Chaque ViewModel enfant contient entre autres une propriété IsSelected. Lorsque cette propriété est affectée, mon ViewModel enfant envoie alors deux messages via mon implémentation du pattern mediator :
    - un premier pour indiquer quel ViewModel est à afficher dans la partie détail
    - un second pour passer les data
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
            public ZoneViewModel(IMessengerService messenger, Zone zone) : base(null)
           {
                _zone = zone;
                PropertyChanged +=
                    (s, e) =>
                    {
                        if (e.PropertyName.Equals("IsSelected") && IsSelected)
                        {
                            _messenger.Send(this, MessengerMessages.SelectedViewModel);
                            _messenger.Send(this, MessengerMessages.SelectedZone, _zone);
                        }
                    };
    Le premier message est consommé par mon ViewModel principal qui contient une propriété CurrentViewModel.
    Le second message est consommé par le ViewModel détail pour récupérer l'objet qu'il doit afficher. (dans mon exemple : DetailZoneViewModel).

    Le problème est que mes deux messages sont traités immédiatement sans laisser une chance à la vue principale d'exécuter le datatemplate qui va instancier DetailZoneView. Donc la 1ère fois, le second message n'est traité par personne. Les fois suivantes, tout se comporte comme prévu.

    Y'a-t'il un moyen de forcer dans un ViewModel l'exécution du code XAML après un RaiseNotifyPropertyChanged avant de rendre la main ? Histoire d'être sûr que mon application est bien dans l'état attendu avant de traiter les messages suivants...

  2. #2
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    Citation Envoyé par sundown Voir le message
    Y'a-t'il un moyen de forcer dans un ViewModel l'exécution du code XAML après un RaiseNotifyPropertyChanged avant de rendre la main ? Histoire d'être sûr que mon application est bien dans l'état attendu avant de traiter les messages suivants...
    Non... Le binding ne s'effectue pas de manière synchrone : quand tu déclenches un PropertyChanged, tu ne peux pas supposer que l'interface est mise à jour immédiatement. L'instruction de mise à jour est envoyée au dispatcher avec la priorité DataBind, et elle sera traitée dès que le dispatcher aura le temps. En pratique, c'est presque instantané, mais le "presque" fait toute la différence...

    Donc il faut essayer une autre approche. En fait, je comprends pas trop pourquoi tu as besoin que DetailZoneView soit instancié ? C'est une vue, et le ViewModel ne devrait pas dépendre d'une vue... C'est le ViewModel qui gère le message, non ? Pas la vue ?

  3. #3
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    8
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 8
    Par défaut
    Citation Envoyé par tomlev Voir le message
    En fait, je comprends pas trop pourquoi tu as besoin que DetailZoneView soit instancié ? C'est une vue, et le ViewModel ne devrait pas dépendre d'une vue... C'est le ViewModel qui gère le message, non ? Pas la vue ?
    En fait j'utilise la librairie MEFedMVVM de Marlon Grech.
    C'est lorsque ma vue DetailZoneView sera instanciée que le ViewModel qui lui est associé sera créé.

    Quand j'envoie l'évènement "SelectedViewModel", mon MainViewModel le récupère et renseigne sa propriété CurrentView. Mon ContentControl, via son DataTemplate va alors instancier DetailZoneView, qui va réclamer à MEF une instance de DetailZoneViewModel, qui va s'abonner à l'évènement "SelectedZone" et va pouvoir ainsi récupérer les données qu'il est censé afficher.
    C'est pourtant simple, non ?

    Bon je sais, on doit sûrement pouvoir faire plus simple et j'ai du partir dans une belle usine à gaz pour pas grand chose...

    C'est juste que, l'intérêt d'utiliser un mediator, c'est de pouvoir découpler les ViewModels entre eux. S'ils sont découplés, qui s'occupe de les instancier à part la View lorsqu'elle s'affiche ? (elle instancie alors son ViewModel dans le codebehind sur l'affectation du DataContext, ou directement dans le XAML).
    Et si la View n'a pas été appelée, le ViewModel qui lui est associé n'existe pas encore et ne peut donc pas consommer le message.

    C'est ça que je n'ai pas compris...

  4. #4
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    Donc la vue est instanciée avant le ViewModel ? ça me semble bizarre, en général on fait le contraire : on crée le ViewModel, et on l'affecte à un ContentControl (ou autre) qui va instancier le DataTemplate correspondant au ViewModel. Mais bon, c'est peut-être différent avec MEFedMVVM, je connais pas...

    C'est vrai que ça a l'air un peu usine à gaz ce truc... j'ai vu passer les articles de Marlon Grech, mais quand j'ai vu le truc j'ai pas eu le courage de lire jusqu'au bout

  5. #5
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    8
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 8
    Par défaut
    Citation Envoyé par tomlev Voir le message
    Donc la vue est instanciée avant le ViewModel ? ça me semble bizarre, en général on fait le contraire : on crée le ViewModel, et on l'affecte à un ContentControl (ou autre) qui va instancier le DataTemplate correspondant au ViewModel. Mais bon, c'est peut-être différent avec MEFedMVVM, je connais pas...
    Je parlais en général, pas spécifiquement dans mon cas. Pour moi, tu as généralement dans ton codebehind un truc du style :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    public MyView() 
    { 
        InitializeComponent(); 
        this.DataContext = new MyViewModel(); 
    }
    Donc c'est bien ta vue qui instancie ton ViewModel.
    Sinon dans mon cas, mon DataTemplate consiste justement en une série de vues. Quand une vue est sélectionnée par mon DataTemplate, le ViewModel qui lui est associé est alors créé. Et mon problème est là : tant que mon DataTemplate n'a pas été exécuté, le ViewModel qui doit consommer mon second message n'est pas encore instancié.

    Citation Envoyé par tomlev Voir le message
    C'est vrai que ça a l'air un peu usine à gaz ce truc... j'ai vu passer les articles de Marlon Grech, mais quand j'ai vu le truc j'ai pas eu le courage de lire jusqu'au bout
    Mon problème n'a rien à voir avec MEFedMVVM. Franchement le boulot que Marlon a fait est excellent. Par contre, sa librairie n'est pas un framework MVVM mais plutôt une librairie pour implémenter MEF par dessus un framework MVVM existant. Tous les services classiques (mediator, dispatcher, etc...) peuvent être importés en une seule ligne de code.
    Ça vaut le coup d'œil

  6. #6
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    Citation Envoyé par sundown Voir le message
    Pour moi, tu as généralement dans ton codebehind un truc du style :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    public MyView() 
    { 
        InitializeComponent(); 
        this.DataContext = new MyViewModel(); 
    }
    Donc c'est bien ta vue qui instancie ton ViewModel.
    Ben moi je fais pas comme ça... je sais que cette approche existe et est assez répandue, mais je préfère largement faire l'inverse : créer le ViewModel et l'attribuer à un ContentControl/ItemsControl/autre (généralement via un binding), et la vue adéquate est automatiquement créée en fonction du type du ViewModel

Discussions similaires

  1. WPF MVVM Binding Refresh
    Par gridin dans le forum Windows Presentation Foundation
    Réponses: 7
    Dernier message: 14/01/2011, 11h26
  2. [WPF & MVVM] Mediator et GC
    Par NeoKript dans le forum Windows Presentation Foundation
    Réponses: 9
    Dernier message: 12/01/2011, 07h52
  3. Probleme de Refresh avec TQuery et DBGrid
    Par insoo dans le forum C++Builder
    Réponses: 7
    Dernier message: 25/11/2003, 17h20
  4. Réponses: 2
    Dernier message: 23/12/2002, 20h34
  5. Sortir d'un progamme qui boucle ou qui refresh
    Par mikevador02 dans le forum C
    Réponses: 12
    Dernier message: 14/12/2002, 09h38

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