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] appliquer un converter a une propriété des éléments d'une collection


Sujet :

Windows Presentation Foundation

  1. #1
    maa
    maa est déconnecté
    Membre actif
    Avatar de maa
    Inscrit en
    Octobre 2005
    Messages
    672
    Détails du profil
    Informations personnelles :
    Âge : 40

    Informations forums :
    Inscription : Octobre 2005
    Messages : 672
    Points : 288
    Points
    288
    Par défaut [WPF] appliquer un converter a une propriété des éléments d'une collection
    Bonjour,

    Dans le cadre du binding avec wpf, j'aimerais appliquer un converter à une propriété des éléments de la collection source d'une listbox. Un exemple sera peut-être plus parlant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    <ListBox ItemsSource="{Binding Path=Customers}" DisplayMemberPath="Salary" />
    J'aimerais applique un converter sur la propriété Salary. Est-ce possible ?

    Merci d'avance pour votre aide.

    mathmax

  2. #2
    Rédacteur
    Avatar de Thomas Lebrun
    Profil pro
    Inscrit en
    Octobre 2002
    Messages
    9 161
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Octobre 2002
    Messages : 9 161
    Points : 19 434
    Points
    19 434
    Par défaut
    Quel intérêt d'avoir un Converter sur Salary ? Si la propriété est de type double/decimal/etc..., la méthode ToString sera appellée automatiquement et l'affichage sera correct.

    A moins que tu ne veuilles parler d'un Template/DataTemplate ?

  3. #3
    maa
    maa est déconnecté
    Membre actif
    Avatar de maa
    Inscrit en
    Octobre 2005
    Messages
    672
    Détails du profil
    Informations personnelles :
    Âge : 40

    Informations forums :
    Inscription : Octobre 2005
    Messages : 672
    Points : 288
    Points
    288
    Par défaut
    Non c'est un objet de type salary, qui en fait contient un dictionnaire comprenant en clé la devise et en valeur le montant du salaire dans la devise. Le converter doit renvoyer simplement le salaire dans la devise courante. Est-ce possible d'applique un converter sur le displaymemberpath ?

  4. #4
    Rédacteur
    Avatar de Thomas Lebrun
    Profil pro
    Inscrit en
    Octobre 2002
    Messages
    9 161
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Octobre 2002
    Messages : 9 161
    Points : 19 434
    Points
    19 434
    Par défaut
    Oui mais je pense que tu va devoir utiliser un DataTemplate pour cela.

    Dans ton DataTemplate, tu devrais faire du binding et là, tu pourras appliquer ton Converter.

  5. #5
    maa
    maa est déconnecté
    Membre actif
    Avatar de maa
    Inscrit en
    Octobre 2005
    Messages
    672
    Détails du profil
    Informations personnelles :
    Âge : 40

    Informations forums :
    Inscription : Octobre 2005
    Messages : 672
    Points : 288
    Points
    288
    Par défaut
    Et ça donnerait quoi ? Ca implique quoi ?

  6. #6
    maa
    maa est déconnecté
    Membre actif
    Avatar de maa
    Inscrit en
    Octobre 2005
    Messages
    672
    Détails du profil
    Informations personnelles :
    Âge : 40

    Informations forums :
    Inscription : Octobre 2005
    Messages : 672
    Points : 288
    Points
    288
    Par défaut
    Ok, ceci marche :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    <ListBox ItemsSource="{Binding Path=Customers}">
    	<ListBox.ItemTemplate>
    		<DataTemplate>
    			<TextBlock Text="{Binding Path=Salary, Converter={StaticResource SalaryConverter}}" />
    		</DataTemplate>
    	</ListBox.ItemTemplate>
    </ListBox>

  7. #7
    Rédacteur
    Avatar de Thomas Lebrun
    Profil pro
    Inscrit en
    Octobre 2002
    Messages
    9 161
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Octobre 2002
    Messages : 9 161
    Points : 19 434
    Points
    19 434
    Par défaut
    Bien joué

    Tout simple non ?


    A+

  8. #8
    maa
    maa est déconnecté
    Membre actif
    Avatar de maa
    Inscrit en
    Octobre 2005
    Messages
    672
    Détails du profil
    Informations personnelles :
    Âge : 40

    Informations forums :
    Inscription : Octobre 2005
    Messages : 672
    Points : 288
    Points
    288
    Par défaut
    En tout cas le databinding avec wpf est vraiment beaucoup plus puissant qu'en windows form. Rien que pour ça, ça vaut le coup de passer a wpf je trouve.
    Merci pour ton aide.

  9. #9
    maa
    maa est déconnecté
    Membre actif
    Avatar de maa
    Inscrit en
    Octobre 2005
    Messages
    672
    Détails du profil
    Informations personnelles :
    Âge : 40

    Informations forums :
    Inscription : Octobre 2005
    Messages : 672
    Points : 288
    Points
    288
    Par défaut
    J'ai un soucis avec la fonction ConvertBack de mon converter.
    Pas de problème avec la fonction Convert : Pour rappel, ma propriété Salary est un dictionnaire comprenant en clé la devise et en valeur le montant du salaire dans la devise. Je dois, à partir de cette propriété Salary, afficher la valeur dans la bonne devise. J'ai pour cela fait un converter par devise.
    Par contre pour la fonction ConvertBack, je dois mettre à jour le dictionnaire à partir de la valeur passée en paramètre. Or je ne peux pas faire cela car dans mon converter je n'ai pas connaissance de l'objet portant la propriété "Salary". Je peux seulement renvoyer un nouveau dictionnaire mais alors ça écraserait le dictionnaire existant et donc les valeurs dans les autres devises... Comment faire.
    PS : ne tient pas compte du fait que j'ai choisit de représenter l'objet Salary par un dictionnaire, c'est juste un exemple pour simplifier mon problème.

  10. #10
    Rédacteur
    Avatar de Thomas Lebrun
    Profil pro
    Inscrit en
    Octobre 2002
    Messages
    9 161
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Octobre 2002
    Messages : 9 161
    Points : 19 434
    Points
    19 434
    Par défaut
    Citation Envoyé par maa Voir le message
    Or je ne peux pas faire cela car dans mon converter je n'ai pas connaissance de l'objet portant la propriété "Salary". Je peux seulement renvoyer un nouveau dictionnaire mais alors ça écraserait le dictionnaire existant et donc les valeurs dans les autres devises... Comment faire.
    Dans ton Converter, tu peux tenter de passer en paramètres à la méthode ConvertBack l'instance de ton dictionnaire: il est en effet possible de passer des paramètres aux Converters.

    A tester....

  11. #11
    maa
    maa est déconnecté
    Membre actif
    Avatar de maa
    Inscrit en
    Octobre 2005
    Messages
    672
    Détails du profil
    Informations personnelles :
    Âge : 40

    Informations forums :
    Inscription : Octobre 2005
    Messages : 672
    Points : 288
    Points
    288
    Par défaut
    C'est ce que je tente de faire, mais ça n'est pas facile :
    Je connais mon dictionnaire via le binding or je ne peux pas passer à ConverterParameter une valeur de binding car ça n'et pas une dependencyProperty.
    Il faudrait alors que j'utilise le multibinding pour passer en paramètre ce dictionnaire... puis dans la méthode ConvertBack il faudrait que je mette à jour ce dictionnaire et que je le retourne. Je vais tenter... Le problème est que j'ai aussi un autre paramètre à passer à mon converter : la devise, or ConverterParameter ne permet de passer qu'un objet...

  12. #12
    Rédacteur
    Avatar de Thomas Lebrun
    Profil pro
    Inscrit en
    Octobre 2002
    Messages
    9 161
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Octobre 2002
    Messages : 9 161
    Points : 19 434
    Points
    19 434
    Par défaut
    En effet, dans ce cas là, tu es coincé

  13. #13
    maa
    maa est déconnecté
    Membre actif
    Avatar de maa
    Inscrit en
    Octobre 2005
    Messages
    672
    Détails du profil
    Informations personnelles :
    Âge : 40

    Informations forums :
    Inscription : Octobre 2005
    Messages : 672
    Points : 288
    Points
    288
    Par défaut
    Y a t-il autre chose qu'un converter que je peux utiliser pour réaliser ce binding ?

  14. #14
    Membre à l'essai
    Inscrit en
    Août 2007
    Messages
    17
    Détails du profil
    Informations forums :
    Inscription : Août 2007
    Messages : 17
    Points : 10
    Points
    10
    Par défaut Pareil que toi !
    J'ai le même souci que toi maa.

    class ClassA
    {
    int index;
    string mon_text_a_afficher_dans_le_controle;
    }


    Sur un controle, j'utilise un multibinding contenant 2 bindings:
    - l'un est une List<ClassA> (relatif à mon DataContext)
    - l'autre est un index (relatif à Self : c'est une propriété de mon controle)

    J'utilise un MultiConverter pour mon multibinding:
    Dans le Convert, je renvoie le champ "mon_text_a_afficher_dans_le_controle" de l'élément de ma liste (1er binding) situé à l'index renseigné (2ème binding).
    Ca marche bien, mais le souci c'est dans le ConvertBack:
    Je n'ai pas accès à ma liste !

    Ce que j'ai fait (mais qui ne me plait pas du tout), c'est que je stocke l'élement de ma liste dans le Convert et c'est celui là que je mets à jour dans le ConvertBack.

    Mais c'est beurk ;o)
    QQun a-t-il une autre idée ?

  15. #15
    maa
    maa est déconnecté
    Membre actif
    Avatar de maa
    Inscrit en
    Octobre 2005
    Messages
    672
    Détails du profil
    Informations personnelles :
    Âge : 40

    Informations forums :
    Inscription : Octobre 2005
    Messages : 672
    Points : 288
    Points
    288
    Par défaut
    J'avais aussi pensé à cette solution mais elle n'est plus envisageable dès lors que tu veux faire du binding avec des contrôle affichant des listes (listbox, combobox, etc...) car alors le converter est utilisé pour plusieurs ligne et tu ne peux plus stocker d'objets dans la méthode convert sans savoir à quelle ligne de ton contrôle ils correspondent dans la méthode convertback. Ça m'intéresserait aussi de savoir si il existe une autre solution que les converter pour ces cas de figure.

  16. #16
    Membre à l'essai
    Inscrit en
    Août 2007
    Messages
    17
    Détails du profil
    Informations forums :
    Inscription : Août 2007
    Messages : 17
    Points : 10
    Points
    10
    Par défaut
    Si je l'ai utilisé pour une combo box :

    J'ai fait 2 multibindings :
    - 1 pour ItemsSource
    - 1 pour SelectedItem

    Si tu veux, je peux te donner + d'infos

    Par-contre j'ai un gros souci auquel je n'avais pas pensé .
    Comme je me binde sur ma Liste de ClassA (qui est en fait une ObservableCollection).
    Eh bien, lorsque la valeur d'un élément change, mon controle n''est pas notifié

    Il me semble que je vais devoir utiliser un mécanisme encore + moche :
    Sur le "Set" de la propriété "Index" de mon controle, je recrée le binding, mais cette fois plus sur la collection, mais directement sur l'élement correspondant à l'index que je viens de "setter".

    Comme l'élément implémente INotifyPropertyChanged, mon controle est rafraichi si l'élement est modifié.
    Et je n'ai plus besoin de multibinding en plus car je suis déjà sur le bon élément de ma collection.

    Mais dans mes rêves les plus fous, je ne créais le binding qu'une seule fois, c'est tellement plus beau

  17. #17
    Membre à l'essai
    Inscrit en
    Août 2007
    Messages
    17
    Détails du profil
    Informations forums :
    Inscription : Août 2007
    Messages : 17
    Points : 10
    Points
    10
    Par défaut
    Pardon, je viens de comprendre ce que tu voulais dire...

    Mais le binding dans les deux sens, tu n'en as pas besoin dans les 2 bindings.
    Ton ConvertBack, tu n'en as besoin que pour le binding à SelectedItem.
    Pour le binding associé à ItemsSource, c'est un mode OneWay.

    Dans le Convert, je stocke l'élement de ma collection qui correspond à l'index, dans une propriéte de ma classe Converter.
    Et c'est ce même élément que je modifie dans le ConvertBack.

    Ca donne un truc dy style :

    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
    38
    39
    40
     
       public class EntireParamsToStringMultiConverter : IMultiValueConverter
        {
              private IValueID found = null;
     
            // 1er element de value = ma collection
            // 2eme element de value = mon id
            public object Convert(object[] value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                ObservableCollection<IValueID> coll;
                UInt16 ref_id;
                string s_ret = null;
     
                found = null;
     
                if ((value[0] is ObservableCollection<IValueID>) &&
                    (UInt16.TryParse(value[1].ToString(), out ref_id)))
                {
                    coll = value[0] as ObservableCollection<IValueID>;
                    found = coll.FirstOrDefault(e => e.Id == ref_id);
     
                    if (found != null)
                    {
                       s_ret = found.Value.ToString();
                    }
                }
     
                return s_ret;
           }
     
            public object[] ConvertBack(object value, Type[] TargetType, object parameter, System.Globalization.CultureInfo culture)
            {
                if (found != null)
                {
                    found.Value = value.ToString();
                }
                return null;
            }
     
        }


    Ca marche mais encore une fois, ça ne me plait pas....

  18. #18
    maa
    maa est déconnecté
    Membre actif
    Avatar de maa
    Inscrit en
    Octobre 2005
    Messages
    672
    Détails du profil
    Informations personnelles :
    Âge : 40

    Informations forums :
    Inscription : Octobre 2005
    Messages : 672
    Points : 288
    Points
    288
    Par défaut
    Dans mon cas, je voulais faire du binding bidirectionnel sur ItemsSource. Et là ta technique n'est plus possible... à moins de passer la propriété SelectedIndex comme troisième valeur... Mais là ça devient franchement bricolage.

    Sinon, j'avais bricolé un truc pour binder des propriété calculée en wpf
    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
        * Tout est dans le zip.
        * Voici comment se fait l'ajout d'une propriété virtuelle :
        *
        * var view = new CollectionView<Company>(MyCollection);
        * view.FakePropertiesDefinitions.Add(
        * "NomDeLaPropriétéVirtuelle",
        * //méthode "get"
        * c =>
        * {
        * view.StoredObject = [n'importe quelle expression : linq ou autre];
        * return [une expression basée sur view.StoredObject];
        * },
        * //méthode "set"
        * value =>
        * {
        * //on peut ici faire toute sorte d'opération de mise à jour sur view.StoredObject
        * });
        *
        * this.DataContext = view;
    L'inconvénient c'est que ça ne s'applique que les objets de la liste du datacontext courant. J'aimerais pouvoir modifier cette source pour appliquer des propriétés calculées à n'importe quel objets correspondant à un path du binding courant.
    Si toutefois tu appliques le binding directement sur le datacontext courant, ma source peut être une solution à ton problème.

Discussions similaires

  1. [Débutant] Somme d'une partie des éléments d'une matrice
    Par pa243 dans le forum MATLAB
    Réponses: 5
    Dernier message: 30/05/2015, 19h39
  2. Réponses: 4
    Dernier message: 01/07/2014, 09h26
  3. Réponses: 5
    Dernier message: 04/03/2014, 16h51
  4. Réponses: 0
    Dernier message: 30/03/2011, 15h11
  5. [DisplayTag] Affichage d'une partie des éléments d'une liste sur un critère
    Par jaguars_s dans le forum Taglibs
    Réponses: 4
    Dernier message: 30/07/2010, 18h15

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