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 :

Binding, classe static et notification


Sujet :

Windows Presentation Foundation

  1. #1
    Membre du Club Avatar de Takumi
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Juin 2009
    Messages
    163
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Juin 2009
    Messages : 163
    Points : 62
    Points
    62
    Par défaut Binding, classe static et notification
    Bonjour,

    Je suis en train de développer une petite application multimédia sous WPF qui me permet de lire pour le moment des fichiers sonores. Dans cette application j'ai une class static qui se charge de gérer la lecture, la pause, le saut en avant ou en arrière d'une chanson, en bref tout ce qui est lié à la lecture des fichiers sonore.

    Ce que je souhaite maintenant faire c'est utiliser cette classe avec le binding de WPF. J'ai fait quelques recherches sur le sujet mais je n'ai rien trouvé qui m’a aidé. Il se trouve que certain champs static sur lequel je souhaite faire un binding puisse changer pendant l'exécution. Or après avoir lu quelques articles et forums j'ai cru comprendre qu'il n'était pas possible de notifier les changements quand le champ était static. En général la solution qui était préconisé consistait à créer une classe en l'instancier et réutiliser les champs static, et faire le binding sur l'instance. Cependant ma classe static commence à être longue, et je ne voudrais pas à avoir à réécrire de trop gros morceau de code.

    Est-ce la seule solution possible? Sinon comment puis-je arriver à mes fins sans devoir tout refaire?

    Je vous remercie d'avance.

  2. #2
    Membre expert
    Avatar de Pragmateek
    Homme Profil pro
    Formateur expert .Net/C#
    Inscrit en
    Mars 2006
    Messages
    2 635
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Formateur expert .Net/C#
    Secteur : Conseil

    Informations forums :
    Inscription : Mars 2006
    Messages : 2 635
    Points : 3 958
    Points
    3 958
    Par défaut
    Es-tu sûr de la viabilité de ta conception ?

    L'utilisation d'une classe static, qui semble être ici un lecteur audio, ne parait pas à priori justifiée.

    A la limite si tu veux garantir l'unicité de ton lecteur utilise un singleton.

  3. #3
    Membre du Club Avatar de Takumi
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Juin 2009
    Messages
    163
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Juin 2009
    Messages : 163
    Points : 62
    Points
    62
    Par défaut
    Si j'ai décidé d'employer une classe static c'était dans le but d'avoir un lecteur audio unique. Cela ne m'était pas utile d'avoir plusieurs lecteurs. Je n'ai jamais utilisé de singleton, mais de ce que j'en ai lu cela consiste à faire en sorte d'avoir toujours qu'une seule instance d'une classe maximum. Cela peut m'intéresser mais est-ce que cela pourra m'aider à mieux répondre à mon problème? Et puis-je réutiliser ma classe static sans avoir à devoir tous changer?

    Merci d'avance.

  4. #4
    Membre expert
    Avatar de Pragmateek
    Homme Profil pro
    Formateur expert .Net/C#
    Inscrit en
    Mars 2006
    Messages
    2 635
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Formateur expert .Net/C#
    Secteur : Conseil

    Informations forums :
    Inscription : Mars 2006
    Messages : 2 635
    Points : 3 958
    Points
    3 958
    Par défaut
    Si j'ai décidé d'employer une classe static c'était dans le but d'avoir un lecteur audio unique. Cela ne m'était pas utile d'avoir plusieurs lecteurs. Je n'ai jamais utilisé de singleton, mais de ce que j'en ai lu cela consiste à faire en sorte d'avoir toujours qu'une seule instance d'une classe maximum.
    Utiliser un singleton te permettras en effet d'obtenir l'unicité que tu souhaites.

    Cela peut m'intéresser mais est-ce que cela pourra m'aider à mieux répondre à mon problème?
    Si ton problème principal est le fait que les attributs auxquels tu accèdes sont static ça le résoudra.

    Et puis-je réutiliser ma classe static sans avoir à devoir tous changer?
    La structure et les traitements restent les mêmes, seule change la façon d'y accéder :
    via la classe auparavant :
    désormais via son unique instance :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Player player = Player.Instance;
    player.Play(...);
    Donc des choses qui dans la majorité des cas se règleront avec un rechercher/remplacer brut de texte.

  5. #5
    Membre du Club Avatar de Takumi
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Juin 2009
    Messages
    163
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Juin 2009
    Messages : 163
    Points : 62
    Points
    62
    Par défaut
    Bonsoir,

    J'ai donc changé ma classe static en singleton.

    Maintenant après avoir un peu cherché à droite à gauche j'ai pu lire qu'il fallait que je mette les champs que je souhaite utiliser pour le binding en tant que DependancyProperty. J'ai donc suivis un peu les tutos que j'ai pu trouver et je suis tombé sur cette article:

    http://www.switchonthecode.com/tutor...ncy-properties

    Dans cette article, quand il explique ce que font SetValue et GetValue l'auteur conseil dans son assesseur de ne mettre que l'une des deux fonctions et pas de code supplémentaire:

    A little bit of a side note here - don't ever put anything but the GetValue and SetValue calls inside the property wrapper. This is because you never know if someone will set the property through the wrapper, or straight through a SetValue call - so you don't want to put any extra logic in the property wrapper. For example, when you set the value of a dependency property in XAML, it will not use the property wrapper - it will hit the SetValue call directly, bypassing anything that you happened to put in the property wrapper.
    Cependant cela me pose quelque problème car pour retourner la valeur ou en assigner une nouvelle j'ai besoin de faire quelques traitement particulier. Pour lire mes fichiers audio j'utilise Fmod, j'ai dans ma classe une instance de la classe Channel qui lit le son, et dans cette classe il y a un getter et un setter pour récupérer le volume ou le changer. Donc auparavant j'avais un assesseur volume qui utilisais les méthode de cette classe Channel. Cela donnait quelque chose comme cela:

    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
     
    public float Volume
            {
                get
                {
                    float Volume = -1f;
                    if(Player._Channel != null)
                        Player._Channel.getVolume(ref Volume);
     
                    return Volume;
                }
     
                set
                {
                    if (Player._Channel != null)
                    {
                        value = Math.Abs(value);
                        Player._Channel.setVolume(value);
                    }
                }
            }
    Maintenant si je souhaite suivre les conseil de l'article cité précédemment je ne vois pas comment je peux reproduire ce que j'avais écrit. Est-il possible d'ajouter une fonction personnalisé lors de l'exécution de SetValue ou GetValue?

    Je vous remercie d'avance.

  6. #6
    Membre expert
    Avatar de Pragmateek
    Homme Profil pro
    Formateur expert .Net/C#
    Inscrit en
    Mars 2006
    Messages
    2 635
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Formateur expert .Net/C#
    Secteur : Conseil

    Informations forums :
    Inscription : Mars 2006
    Messages : 2 635
    Points : 3 958
    Points
    3 958
    Par défaut
    Dans ce cas tu ne devrais pas en effet utiliser de DP, il serait plus adapté d'implémenter le pattern observer, ie faire implémenter INotifyPropertyChanged à ton player, et notifier chaque fois qu'une propriété, comme le volume, change.

  7. #7
    Membre du Club Avatar de Takumi
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Juin 2009
    Messages
    163
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Juin 2009
    Messages : 163
    Points : 62
    Points
    62
    Par défaut
    D'accord, je vais me renseigner sur tout cela. Mais est-ce que tout comme les DependancyProperty il est possible de faire un binding aussi simplement depuis le code xaml si j'implemente INotifyPropertyChanged?

  8. #8
    Membre actif
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    203
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2007
    Messages : 203
    Points : 220
    Points
    220
    Par défaut
    Mais est-ce que tout comme les DependancyProperty il est possible de faire un binding aussi simplement depuis le code xaml si j'implemente INotifyPropertyChanged?
    Oui, coté xaml il n'y pas de différence

  9. #9
    Membre du Club Avatar de Takumi
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Juin 2009
    Messages
    163
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Juin 2009
    Messages : 163
    Points : 62
    Points
    62
    Par défaut
    Bonsoir,

    Je me suis donc renseigné sur INotifyPropertyChanged. Tout d'abord j'ai trouvé quelques articles interessant qui montrés comment éviter d'avoir à toujours réecrire l'implémentation de l'interface. J'en avais trouvé un assez intéressant qui automatisé très bien la tâche mais nécessitait d'utiliser d'autre outils supplémentaire. Cela est certainement intéressant mais n'ayant que peu d'expérience dans ce que je souhaite faire je verrais cela plus tard quand j'arriverais déjà à le faire à peu près correctement de façon plus classique. J'ai donc opté pour une classe de base qui implémente l'interface et que ma classe Player va hérité.

    J'ai donc ensuite tenté de faire un binding depuis mon code xaml. J'ai voulus essayer d'afficher la valeur du volume dans un TextBlock. J'ai donc tout d'abord ajouté un champs Player dans la classe de ma fenêtre. Le bout de code xaml ressemble à cela:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    <TextBlock Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=pla.Volume,
                                            diag:PresentationTraceSources.TraceLevel=High}"></TextBlock>
    Je lance pour tester, et paf une erreur. Le path indiqué n'est pas trouvé. Je ne comprenais pas pourquoi, ce que je voulais faire c'était indiquer le nom du champs en pensant qu'il irait le chercher. Mais après j'ai testé en mettant à la place un assesseur et là miracle ça marche. Donc quand on souhaite faire un binding cela ne se fait que sur un assesseur?

    Ensuite je rencontre un problème d'un autre type. J'ai donc une classe de type Channel qui se charge de lire le fichier sonore. Cette classe peut être null comme elle pourrait avoir quelque chose. C'est aussi cette même classe qui par exemple me permet de régler le volume et connaitre sa valeur. Voici l'assesseur que j'ai crée concernant ce volume:

    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 float Volume
            {
                get
                {
                    float Volume = -1f;
                    if(this._Channel != null)
                        this._Channel.getVolume(ref Volume);
     
                    return Volume;
                }
     
                set
                {
                    if (this._Channel != null)
                    {
                        value = Math.Abs(value);
                        this._Channel.setVolume(value);
                        this.RaisePropertyChanged("Volume");
                    }
                }
            }
    Dans le getter je test justement que le champ de type Channel n'est pas null avant d'essayer d'extraire la valeur du volume. Mon problème intervient quand je souhaite justement lire un nouveau fichier sonore, la classe est instancié mais le volume ne sera pas assigné en passant par mon assesseur (à moins que l'utilisateur le change) ce qui fait par exemple que la valeur renvoyée peut toujours être -1. Pour le moment la seule solution que j'ai trouvé est de devoir réassigner le volume en passant par mon assesseur quitte à devoir redonner la valeur actuelle du volume. Pas top comme solution. Comment pourrais je faire ici pour "rafraichir", ou signaler qu'il y a eu un changement?

    Je vous remercie d'avance pour votre aide.

  10. #10
    Membre du Club Avatar de Takumi
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Juin 2009
    Messages
    163
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Juin 2009
    Messages : 163
    Points : 62
    Points
    62
    Par défaut
    Bonsoir,

    Je suis désolé de remonter le sujet mais je n'avance pas sur ce problème. Je me demandais est-il possible de faire une sorte de refresh générale pour les binding? Par contre si cela est possible cela ne risque pas t-il d'être très couteux en terme de performance à partir du moment où l'on en a beaucoup dans son application?

    Je vous remercie d'avance.

  11. #11
    Membre expérimenté
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    1 103
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 1 103
    Points : 1 561
    Points
    1 561
    Par défaut
    Si tes propriétés qui "fluctuent" dans le temps on une alerte de type INotifyPropertyChanged...

    il n'y a pas besoin de Refresh... le simple fait qu'elle change aussi bien du coté UI que tu coté Player fait qu'elles seront normalement synchrones...
    Avec toutefois une obligation...
    Sur certains controles WPF tu trouvera une propriété du genre IsSynchronizedWithCurrentItem... si tel est le cas comme les listbox, les combobox ... il est INDISPENSABLE de leur affecter True. Sinon tu notera que le composant ignore les modifications apportées dans le DataContext directement, donc la source du binding.
    Parfois il faut également ordonner une liaison en mode Mode=TwoWay de façon à ce que la liaison soit automatiquement dans les 2 sens, et pas uniquement dans le sens Source -> UI ou UI -> Source.

    {Binding propriete, Mode=TwoWay}

    Attention, certains composants lorsque tu utilise le TwoWay ne fonctionnent pas correctement sur des propriétés normales, et il peut être alors utile de passer par des propriétés de dépendances, mais dans ton cas, je ne pense pas que tu sois confronter à cette situation...

  12. #12
    Membre du Club Avatar de Takumi
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Juin 2009
    Messages
    163
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Juin 2009
    Messages : 163
    Points : 62
    Points
    62
    Par défaut
    Bonjour,

    Merci pour ta réponse. Concernant INotifyPropertyChanged et le changement de valeur au cours du temps j'avais compris le principe. Je vais essayer de donner un exemple complet pour illustrer mon problème. Par exemple j'ai une classe de type Channel qui lis des flux audio (j'utilise Fmod pour précision). Cette classe peut me donner par exemple la position actuelle de la chanson (en milliseconde par exemple). Donc dans ma classe Player j'ai voulus créer un assesseur sur la position afin de pouvoir la connaitre ou encore la changer:

    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
     
    public uint Position
            {
                get 
                {
                    uint Position = 0;
                    if (this._Channel != null)
                        this._Channel.getPosition(ref Position, TIMEUNIT.MS);
     
                    return Position;
                }
     
                set
                {
                    if (this._Channel != null)
                        this._Channel.setPosition(value, TIMEUNIT.MS);
                }
            }
    Le problème est qu'ici la valeur de Position dans l'instance de la classe Channel va changer en cours de lecture mais je n'ai aucun moyen d'en être informé. Pour le moment la seule astuce que j'ai pu trouver c'est un Timer qui tourne derrière et déclenche un event toutes les secondes sur lequel ma classe Window vient s'abonner. Car si je fait un binding, la première fois il va tenter de récupérer la valeur, mais après plus rien car il n'y aura jamais aucun notification de changement car tous se passe en interne dans la classe Channel.

  13. #13
    Membre expérimenté
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    1 103
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 1 103
    Points : 1 561
    Points
    1 561
    Par défaut
    C'est un problème inhérent à fmod qui ne te transmet pas d'évenement de progression...

    a part un thread d'arrière plan qui fait une attente active mais ca c'est le pire scénario... ou un timer, il n 'ya pas d'autre solution pour connaitre coté channel la position exacte dans le temps sans faire intervenir l'utilisateur, mais l'ui ne rechargera pas de lui meme s'il ne recoit pas de notification de changement...
    maintenant je comprend mieux ton problème

    C'est à toi de faire cette logique et effectivement le timer est la meilleur solution pour palier au manque de la plateforme que tu utilise.

Discussions similaires

  1. Class static = instance unique ?
    Par maa dans le forum C#
    Réponses: 36
    Dernier message: 30/09/2007, 00h46
  2. Réponses: 4
    Dernier message: 27/07/2007, 20h34
  3. Réponses: 15
    Dernier message: 06/04/2006, 12h05
  4. [Info] variable d'une classe static
    Par romdelf dans le forum Langage
    Réponses: 21
    Dernier message: 06/12/2005, 15h08
  5. Pb accès entre 2 classes static
    Par d.w.d dans le forum C++
    Réponses: 5
    Dernier message: 23/02/2005, 19h05

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