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 :

[WPF & MVVM] Mediator et GC


Sujet :

Windows Presentation Foundation

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2007
    Messages
    634
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2007
    Messages : 634
    Par défaut [WPF & MVVM] Mediator et GC
    Bonsoir à tous,

    j'ai un petit soucis lors de l'utilisation d'un mediator.

    J'ai une classe Plugin qui contient ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    public void Associate(String Identifiant, String Header, String Content)
            {
                Messenger.Instance.Register(Identifiant, delegate
                {
                    Messenger.Instance.Notify(MediatorMessages.MainWindows_SetHeader, "pack://application:,,,/" + this.Namespace + ";component" + Header);
                    Messenger.Instance.Notify(MediatorMessages.MainWindows_SetContent, "pack://application:,,,/" + this.Namespace + ";component" + Content);
                });
            }
    Et une classe loader qui contient :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    public class Loader : Plugin
        {
            public Loader()
            {
                this.Namespace = "Cinema.Plugin";
                this.Associate("Add", "/Headers/HeaderAdd.xaml", "/Contents/Add.xaml");
            }
        }
    Lorsque le message "Add" est emis, la méthode n'est pas appelé car il semblerait que l'objet ne soit plus en vie (qu'il ai été collecté alors qu'il ne l'est pas).

    Maintenant, si je fait ceci à la place :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class Loader : Plugin
        {
            public Loader()
            {
                this.Namespace = "Cinema.Plugin";
                Messenger.Instance.Register(Identifiant, delegate
                {
                    Messenger.Instance.Notify(MediatorMessages.MainWindows_SetHeader, "pack://application:,,,/" + this.Namespace + ";component" + "/Headers/HeaderAdd.xaml");
                    Messenger.Instance.Notify(MediatorMessages.MainWindows_SetContent, "pack://application:,,,/" + this.Namespace + ";component" + "/Contents/Add.xaml");
                });
            }
        }
    Tout fonctionne à merveille, pouvez vous me dire quel est le problème lorsque que je met le Register dans la classe mère ?? (qui est dans une autre assembly, je sais pas si ça peut jouer).


    Merci d'avance.

    Cordialement,
    NeoKript

  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
    J'ai peut-être une idée, mais sans garantie que c'est bien ça le problème...

    La classe Messenger utilise le pattern WeakEvent, pour éviter les fuites mémoires. Cela signifie qu'il ne conserve pas de références fortes aux handlers des messages, mais seulement des WeakReference. Comme tu t'abonnes au message avec une méthode anonyme qui capture des variables locales, le compilateur crée (de façon "invisible" pour toi) un nouvel objet anonyme qui va contenir ces variables. Mais toi, tu passes juste le delegate à la méthode Register, et tu ne conserves pas de référence à l'objet anonyme. Il n'existe donc aucune référence à cet objet, et donc rien qui l'empêche d'être collecté.

    (certes, ça n'explique pas pourquoi ça fonctionne dans le 2e cas...)

    A priori, si tu utilisais une "vraie" méthode au lieu d'une méthode anonyme, ça devrait fonctionner. Mais vu que tu as besoin de capturer des variables locales, ça ne va pas être possible...

    Une autre solution serait de garder une référence vers le delegate lui-même, pour éviter que l'objet ne soit collecté. Un truc dans ce style :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    Action _registeredAction;
     
    public void Associate(String Identifiant, String Header, String Content)
            {
                Action action = delegate
                {
                    Messenger.Instance.Notify(MediatorMessages.MainWindows_SetHeader, "pack://application:,,,/" + this.Namespace + ";component" + Header);
                    Messenger.Instance.Notify(MediatorMessages.MainWindows_SetContent, "pack://application:,,,/" + this.Namespace + ";component" + Content);
                }
                Messenger.Instance.Register(Identifiant, action);
                _registeredAction = action;
            }
    Il faudrait peut-être plutôt faire ça avec une liste d'action, vu que je suppose que la méthode Associate sera appelée plusieurs fois...

  3. #3
    Membre éclairé
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2007
    Messages
    634
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2007
    Messages : 634
    Par défaut
    Salut,

    Et merci pour ta réponse.
    En effet, le problème viens de là !

    Je viens de tester ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    public void Associate(String Identifiant, String Header, String Content)
            {
                Messenger.Instance.Register(Identifiant, Param => this.SetContent());
            }
     
            private void SetContent()
            {
                Messenger.Instance.Notify(MediatorMessages.MainWindows_SetHeader, "pack://application:,,,/" + this.Namespace + ";component" + "/Headers/HeaderAdd.xaml");
            }
    Et ça fonctionne parfaitement, mais dès qu'on fait passer une variable de la méthode, plus rien ...

    Mais du coup, en effet je ne comprend pas pourquoi cela fonctionnait dans le second cas ...

    Ton exemple fonctionne, du coup je vais stocké les Actions dans une List<>...

    Par contre, si quelqu'un sait pourquoi ça fonctionnais quand c'était dans la même classe je suis preneur (à cause de la pile qui contenait encore les valeur... bizarre quand même)

    Merci

  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
    Citation Envoyé par NeoKript Voir le message
    (à cause de la pile qui contenait encore les valeur... bizarre quand même)
    Ca pourrait être un truc comme ça...

    Si tu veux une réponse d'expert, tu peux poser la question sur Stack Overflow (en anglais bien sûr). Il y a très souvent des grosses pointures qui viennent répondre aux questions (genre Eric Lippert, Jon Skeet...)

  5. #5
    Membre émérite Avatar de jmix90
    Homme Profil pro
    Consultant .Net
    Inscrit en
    Juillet 2007
    Messages
    576
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Consultant .Net
    Secteur : Conseil

    Informations forums :
    Inscription : Juillet 2007
    Messages : 576
    Par défaut
    Une idée en lisant le code :

    Dans le deuxième exemple, tu ne passes pas le namespace comme une String mais via une référence "this" et cela doit maintenir en vie ton delegate car il contient une référence vers un objet encore en vie.

    Dans le premier exemple, tu passes le namespace en tant que valeur (String) et le delegate n'est peut être pas maintenu en vie.

    Si tu passes les paramètres en tant que reference(ref) peut être que cela fonctionnera ?

    Bon courage !

  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 jmix90 Voir le message
    cela doit maintenir en vie ton delegate car il contient une référence vers un objet encore en vie.
    Ben non... le fait d'avoir une référence vers un objet en vie n'empêche pas d'être collecté par le GC, c'est dans l'autre sens que ça se passe. Il faut qu'un objet en vie ait une référence vers le delegate pour l'empêcher d'être collecté

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

Discussions similaires

  1. WPF TabControl MVVM plusieurs types d'objets
    Par CaptainChoc dans le forum Windows Presentation Foundation
    Réponses: 1
    Dernier message: 23/07/2011, 18h21
  2. Réponses: 4
    Dernier message: 14/06/2011, 11h44
  3. passage WinForm en WPF avec MVVM
    Par dominiqueFaure dans le forum Windows Presentation Foundation
    Réponses: 13
    Dernier message: 23/03/2011, 14h22
  4. [C#] combobox WPF modèle MVVM
    Par july4474 dans le forum Windows Presentation Foundation
    Réponses: 4
    Dernier message: 29/11/2010, 18h16
  5. [MVVM] Mediator et refresh de l'UI
    Par sundown dans le forum Windows Presentation Foundation
    Réponses: 5
    Dernier message: 26/05/2010, 00h28

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