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] ComboBox, binding avec association LINQ


Sujet :

Windows Presentation Foundation

  1. #1
    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
    Points : 39 753
    Points
    39 753
    Par défaut [WPF] ComboBox, binding avec association LINQ
    Salut,

    J'ai créé une fenêtre pour éditer des objets Movie (dont le code est généré avec LINQ To SQL). Quand j'affiche la fenêtre, je mets mon objet Movie dans le DataContext de la fenêtre. Chaque champ de ma fenêtre est bindé sur une propriété de mon objet. Pour les simples champs texte, pas de problème... là où ça coince, c'est pour les propriétés qui correspondent à des associations.

    Par exemple, Movie a une association vers Director. Le designer LINQ m'a généré une propriété DirectorId (qui correspond à un champ de la table movie), et une propriété Director (qui correspond au réalisateur "pointé" par DirectorId).

    Je voudrais que le champ servant à changer le réalisateur soit un ComboBox permettant de sélectionner un réalisateur existant. J'ai donc créé mon combo de la façon suivante :

    Code XML : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
            <ComboBox ItemsSource="{Binding Directors, Source={StaticResource db}}"
                      SelectedItem="{Binding Director}" IsEditable="True" />
    La liste est bien remplie avec les réalisateurs définis dans la base, mais le réalisateur du film en cours d'édition n'est pas sélectionné... en revanche, si j'en sélectionne un dans la liste, la modification est bien répercutée sur mon objet Movie...

    J'ai aussi essayé cette méthode là :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
            <ComboBox ItemsSource="{Binding Directors, Source={StaticResource db}}"
                      DisplayMemberPath="Name"
                      SelectedValuePath="Id"
                      SelectedValue="{Binding DirectorId}" IsEditable="True" />
    Dans ce cas, mon réalisateur est bien sélectionné... mais si j'en choisis un autre, seule la propriété DirectorId est modifié, pas la propriété Director... si bien que mon objet est dans un état incohérent, puisque l'id et le réalisateur ne correspondent plus. J'ai regardé le code généré par le designer LINQ, et effectivement une modification de DirectorId ne met pas à jour Director. Par contre une modification de Director met à jour DirectorId... Bien sûr, je pourrais implémenter la méthode partielle OnDirectorIdChanged pour forcer la mise à jour de Director, mais je me dis qu'il doit y avoir plus simple...

    Donc, en résumé, je voudrais :
    - que le réalisateur actuel du film soit automatiquement sélectionné
    - que la sélection d'un autre réalisateur dans la liste change la propriété Director du film
    Et tout ça, bien sûr, uniquement en XAML de préférence...

    Si vous avez des idées ça me rendrait bien service, parce que moi je commence à être à court...

    Merci d'avance

  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
    Je ne garantie pas d'avoir out saisi mais ca:

    Citation Envoyé par tomlev Voir le message
    Donc, en résumé, je voudrais :
    - que le réalisateur actuel du film soit automatiquement sélectionné
    - que la sélection d'un autre réalisateur dans la liste change la propriété Director du film
    Ca me fait penser à l'implémentation d'un Converter et des méthodes Convert et ConvertBack....

  3. #3
    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
    Points : 39 753
    Points
    39 753
    Par défaut
    OK merci, je vais essayer ça.
    Mais si je pouvais trouver une méthode en pur XAML ce serait encore mieux... surtout que je ne vois pas ce qui cloche avec la première méthode que j'ai utilisée ! Le binding doit être correct, puisque la source est bien mise à jour quand je change l'item sélectionné.
    Pour en avoir le coeur net, j'ai fait le test suivant :
    • j'ai mis point d'arrêt dans l'évènement DataContextChanged de ma fenêtre
    • dans la fenêtre d'exécution (immediate window), j'ai explicitement assigné SelectedItem (entre temps j'ai donné un nom au combo pour que ce soit plus pratique) :
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      cmbDirector.SelectedItem = (DataContext as Movie).Director
      Ca me renvoie bien le réalisateur de mon film
    • tout de suite après, je teste la valeur de SelectedItem :
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      cmbDirector.SelectedItem
      Ca me renvoie null

    Donc en gros le framework refuse d'affecter la valeur que je veux au SelectedItem, bien que la valeur que je mets soit dans la collection Items... je comprends vraiment pas

  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
    Points : 39 753
    Points
    39 753
    Par défaut
    J'ai trouvé

    Citation Envoyé par moi
    bien que la valeur que je mets soit dans la collection Items
    J'avais parlé un peu vite...

    Après de laborieux tests de débogage, je me suis rendu compte que le Director présent dans cmbDirector.Items n'était pas égal à celui du DataContext : ReferenceEquals renvoie false. Je comprends pas trop pourquoi d'ailleurs... visiblement c'est une copie, tous les champs sont égaux !

    Donc j'ai redéfini la méthode Equals de ma classe Director de façon à ce qu'il compare juste l'Id. Et ça marche nickel

    C'est un peu dommage que ce ne soit pas automatique d'ailleurs : 2 objets LINQ de même type avec la même valeur pour la clé primaire devraient être considérés comme égaux il me semble...

  5. #5
    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
    Points : 39 753
    Points
    39 753
    Par défaut
    Citation Envoyé par moi Voir le message
    C'est un peu dommage que ce ne soit pas automatique d'ailleurs : 2 objets LINQ de même type avec la même valeur pour la clé primaire devraient être considérés comme égaux il me semble...
    Faut pas laisser les bonnes idées se perdre... Allez hop, c'est parti
    J'ai créé cette classe (complètement réutilisable a priori...) et j'en ai fait hériter toutes mes classes LINQ To SQL :
    Code C# : 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
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
     
        public abstract class LinqUniqueObject
        {
            private bool IsPrimaryKey(MemberInfo m)
            {
                // Check if the field or property has the ColumnAttribute
                // attribute with the IsPrimaryKey property set to true
                return m.GetCustomAttributes(typeof(ColumnAttribute), true)
                        .Cast<ColumnAttribute>()
                        .Any(a => a.IsPrimaryKey);
            }
     
            private IEnumerable<MemberInfo> GetPrimaryKeyMembers()
            {
                // Find all primary key members
                var members = from m in this.GetType().GetMembers()
                              where IsPrimaryKey(m)
                              select m;
                return members;
            }
     
            public override bool Equals(object obj)
            {
                // Different types => not equal
                if (obj.GetType() != this.GetType())
                {
                    return false;
                }
                else
                {
                    IEnumerable<MemberInfo> pkeys = GetPrimaryKeyMembers();
     
                    if (pkeys.Count() == 0)
                    {
                        // No primary key => use default implementation
                        return base.Equals(obj);
                    }
                    else
                    {
                        // Compare each primary key property
                        foreach (var prop in pkeys.OfType<PropertyInfo>())
                        {
                            object v1 = prop.GetValue(obj, null);
                            object v2 = prop.GetValue(this, null);
                            if (v1 != null && v2 != null)
                            {
                                if (!v1.Equals(v2))
                                    return false;
                            }
                            else if (v1 != null || v2 != null)
                            {
                                // One is null, the other is not => not equal
                                return false;
                            }
                        }
                        // Compare each primary key field
                        foreach (var fld in pkeys.OfType<FieldInfo>())
                        {
                            object v1 = fld.GetValue(obj);
                            object v2 = fld.GetValue(this);
                            if (v1 != null && v2 != null)
                            {
                                if (!v1.Equals(v2))
                                    return false;
                            }
                            else if (v1 != null || v2 != null)
                            {
                                // One is null, the other is not => not equal
                                return false;
                            }
                        }
                        return true;
                    }
                }
            }
        }

    Ca compare tous les champs marqués comme PrimaryKey, renvoie true s'ils sont égaux, et faux sinon. J'ai pas encore testé de façon approfondie (toutes mes tables ont juste une clé primaire de type entier), mais ça a l'air de bien marcher jusqu'ici. Par contre niveau performance c'est sans doute pas terrible, mais pour l'utilisation que j'en fait ça va très bien.

    Par contre, en principe quand on override Equals, il faut aussi overrider GetHashCode (sinon warning à la compilation). Je l'ai fait, mais je suis pas très content de mon implémentation alors je l'ai pas mise ici...

    EDIT: en plus des namespaces habituels, il faut ajouter ceux-ci:
    Code C# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    using System.Reflection;
    using System.Data.Linq.Mapping;

  6. #6
    Membre éprouvé Avatar de anthyme
    Homme Profil pro
    Inscrit en
    Mars 2004
    Messages
    1 559
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2004
    Messages : 1 559
    Points : 1 257
    Points
    1 257
    Par défaut
    Citation Envoyé par tomlev Voir le message
    C'est un peu dommage que ce ne soit pas automatique d'ailleurs : 2 objets LINQ de même type avec la même valeur pour la clé primaire devraient être considérés comme égaux il me semble...
    Passe a linq to Entities

    Les objets sont détachables et atachables au contexte à la volé.

  7. #7
    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
    Points : 39 753
    Points
    39 753
    Par défaut
    Citation Envoyé par anthyme Voir le message
    Passe a linq to Entities
    Oui, il faudrait que je m'y mette...

  8. #8
    Membre éprouvé Avatar de anthyme
    Homme Profil pro
    Inscrit en
    Mars 2004
    Messages
    1 559
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2004
    Messages : 1 559
    Points : 1 257
    Points
    1 257
    Par défaut
    Franchement c'est pas dur et le gain est important ...

    J'ai migré un projet de linq to SQL a linq to entities en changeant dans les 10% de code d'accès aux données

  9. #9
    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
    Points : 39 753
    Points
    39 753
    Par défaut
    J'ai trouvé un article intéressant sur le choix entre Linq To SQL et Linq To Entities :
    http://dotnetaddict.dotnetdevelopers...vs_linqsql.htm

    Mais dans mon cas je suis pas sûr que ça apporte grand chose...

    Concernant mon problème ci-dessus, il y a quand même quelque chose qui me surprend : il me semblait que LINQ To SQL gérait l'identité des objets de la base, donc j'aurais jamais dû me retrouver avec 2 instances d'objets qui représentent toutes les 2 le même réalisateur "Tim Burton"...
    Est-ce que tu crois que Linq to Entities règlerait ce problème ?

  10. #10
    Membre éprouvé Avatar de anthyme
    Homme Profil pro
    Inscrit en
    Mars 2004
    Messages
    1 559
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2004
    Messages : 1 559
    Points : 1 257
    Points
    1 257
    Par défaut
    ton article a presque 2 ans alors fait attention a ce qu'il dit

    sinon moi de ce que je sais c que linq to sql est une ébauche a linq to entities qui est beaucoup plus "pro" (real applications) et qu'il implémente tout ce qui est requis dans un vrai ORM.

    Moi je pense que tu peux tester tu genere les class d entités a partir de la base puis tu fait une requete linq quasi comme en linq to sql et t aura ta réponse

  11. #11
    Futur Membre du Club
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Octobre 2006
    Messages
    12
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Pas de Calais (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Octobre 2006
    Messages : 12
    Points : 7
    Points
    7
    Par défaut
    Citation Envoyé par tomlev Voir le message
    Donc en gros le framework refuse d'affecter la valeur que je veux au SelectedItem, bien que la valeur que je mets soit dans la collection Items... je comprends vraiment pas
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    IsSynchronizedWithCurrentItem="True"
    J'ai dit une betise ?

  12. #12
    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
    Points : 39 753
    Points
    39 753
    Par défaut
    Citation Envoyé par Goj17 Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    IsSynchronizedWithCurrentItem="True"
    J'ai dit une betise ?
    J'ai essayé... ça n'a pas du tout donné ce que je voulais. La première fois que j'affichais la fenêtre d'édition ça sélectionnait toujours le premier réalisateur de la liste. Les fois suivantes ça n'en sélectionnait aucun.

    Mais bon, de toutes façons, j'ai résolu le problème en overridant Equals dans mes classes LINQ...

    D'ailleurs j'ai honteusement oublié le tag résolu, alors que ma propre signature rappelle de ne pas l'oublier ... honte sur moi

    C'est réparé

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

Discussions similaires

  1. Binding avec ComboBox
    Par myCollections dans le forum Windows Presentation Foundation
    Réponses: 7
    Dernier message: 04/11/2010, 17h58
  2. [WPF] Problème de binding avec une classe perso
    Par JuTs dans le forum Windows Presentation Foundation
    Réponses: 5
    Dernier message: 12/04/2010, 18h45
  3. WPF + mdb >> binding combobox
    Par waspy59 dans le forum Windows Workflow Foundation
    Réponses: 0
    Dernier message: 27/10/2009, 00h31
  4. Combobox constant binding avec un champ de db
    Par loulouklm dans le forum Windows Presentation Foundation
    Réponses: 4
    Dernier message: 12/05/2009, 18h18
  5. wpf binding avec un dataset sans listbox
    Par ZashOne dans le forum Windows Presentation Foundation
    Réponses: 2
    Dernier message: 25/12/2007, 19h09

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