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

C# Discussion :

[Binding] lier un contrôle à une propriété de type dictionary


Sujet :

C#

  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 [Binding] lier un contrôle à une propriété de type dictionary
    Bonjour,

    J'ai une classe "MyClass" avec une propriété "Text" de type
    Dictionary<Iso, string> où Iso est une énumération contenant le code iso de pays. Cette propriété contient un texte traduit dans différentes langues.

    J'aimerais binder le texte français de cette classe à un control. C'est à dire binder Text[Iso.fra] à un contrôle.

    Je ne vois pas comment faire ça simplement...

    Quelqu'un a une idée ?

    merci d'avance.
    ****************************************

    - I don’t write plumbing code anymore
    - I use PostSharp
    - And you?


    ****************************************

  2. #2
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Septembre 2007
    Messages
    27
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2007
    Messages : 27
    Points : 33
    Points
    33
    Par défaut
    Salut,

    Tu ne peux pas binder un dictionary<x,y>. Par contre, ce que tu peux faire, c'est créer une List<KeyValuePair<x,y>>, et volriser les DataValue et Displaymember avec "Key" et "Value". Mais c'est très laid, et très bricolo...

    Si ton problème vient juste de la gestion des différentes langues, connais-tu la gestion des ressources localisées avec les fichiers .resx? C'est vraiment le plus simple.

    dans ce cas la propriété 'Text' de ta classe deviendra comme ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public string Text
            {
                get
                {
                    return MesRessources.Untexte;
                }
     
                set
                {
                    MesRessources.Untexte = value;
                    MesRessources.default.Save();
                }
            }
    , où Mesressources est un fichier .resx géré par VS. Tu n'as plus à t'occuper de la langue à choisir, c'est VS qui va chercher le fichier correpondant à la culture en cours. A moins que tu veuilles une culture précise, auquel cas tu peux forcer ça avec la classe RessourceManager.

  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
    Mes textes viennent directement de la base de données via nhibernate. Je sais pas si tu connais le mapping objet relationnel, mais je ne vois vraiment pas comment faire pour les textes soient automatiquement insérer dans le bon fichier resx... La structure de ma table Texts et comme ceci :

    Produit_Id : clef étrangère de la table produit. Chaque ligne de la table produit étant mappée à une classe Produit.
    Lang : code iso de la culture dans laquelle le texte est traduit
    Text : text traduit dans la bonne culture.

    A moins que je fasse deux propriétés : une de type Dictionary pour le chargement de mes données et une qui utilise les fichier Ressource... mais là aussi c'est un poil bricolo.
    ****************************************

    - I don’t write plumbing code anymore
    - I use PostSharp
    - And you?


    ****************************************

  4. #4
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Septembre 2007
    Messages
    27
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2007
    Messages : 27
    Points : 33
    Points
    33
    Par défaut
    Alors ça dépend si tu as besoin de 'switcher' entre des langues différentes, ou pas. Parce que si tel n'est pas le cas (aucun changement de langue entre le moment où tu instancies les objets, et celui où tu les tues), tu peux essayer un truc que j'avais fait pour un cas similaire : j'avais viré de la base de données les traductions. J'ai créé un fichier XML pour chaque langue, avec une colonne id (la même que celle de la BD), et une colonne 'text'. Je chargeais le fichier XML voulu au premier appel à la méthode de ma classe factory. En gros, séparer les données traduites/susceptibles d'être traduites, et celles fixes (nombres, dates au format datetime, etc).

    Si tu ne peux/tu ne veux pas toucher à la structure de ta BD, et que tu es obligé pour une raison x ou y de rapatrier toutes les traductions, tu peux créer une méthode qui renvoie un objet 'bindable' (IList) en fonction de l'élément de ton enum ISO qui serait passé en paramètre.

  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
    Je souhaite en effet rapatrier toutes les traductions dans mes objets car je veux switcher facilement la langue et j'ai même souvent besoin d'avoir les 2 en même temps.
    Je ne peux pas non plus me permettre de supprimer des infos de ma base de données.
    donc le dictionary me parait approprié.
    Pour ce qui est de ta méthode, je ferais plutôt une propriété comme ça je peux la binder, non ?
    ****************************************

    - I don’t write plumbing code anymore
    - I use PostSharp
    - And you?


    ****************************************

  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
    Bon, j'ai finalement réussi à binder mon dictionary à mon contrôle. En fait pas directement, mais par l'intermédiaire d'une classe "LanguageBindingSource" que j'ai écrite et dans laquelle je réécrit les PropertyDescriptor des objet de ma collection en remplaçant celui qui correspond à ma propriété Dictionary par une classe qui dérive de PropertyDescriptor et qui renvoi le texte du Dictionary dans la bonne langue. Il faut évidement préciser la langue au niveau de LanguageBindingSource.
    Voici la méthode GetItemProperties de ITypedList :

    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
    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 PropertyDescriptorCollection GetItemProperties(PropertyDescriptor[] listAccessors)
            {
                PropertyDescriptorCollection sourceProps;
                if (dataSource == null)
                    sourceProps = PropertyDescriptorCollection.Empty;
     
                object obj1 = ListBindingHelper.GetList(this.dataSource);
     
                sourceProps = ListBindingHelper<T>.GetListItemProperties(obj1, listAccessors);
     
                var cust = new CustomTypePropertyDescriptor<T>(this, GetType(), dataMember, typeof(string));
     
                PropertyDescriptor[] props = new PropertyDescriptor[sourceProps.Count];
                for (int i = 0; i < sourceProps.Count; i++)
                {
                    if(sourceProps[i].Name == dataMember)
                        props[i] = cust;
                    else
                        props[i] = sourceProps[i];
                }
     
                return new PropertyDescriptorCollection(props);
            }
     
            private class CustomTypePropertyDescriptor<T> : PropertyDescriptor
            {
                public CustomTypePropertyDescriptor(LanguageBindingSource<T> owner, Type componentType, string propertyName, Type propertyType)
                    : base(propertyName, null)
                {
                    this.propertyType = propertyType;
                    this.componentType = componentType;
                    this.owner = owner;
                }
     
                private Type propertyType;
                private Type componentType;
                private LanguageBindingSource<T> owner;
     
                public override object GetValue(object component)
                {
                    return ((IDictionary<Iso, string>)typeof(T).GetProperty(owner.DataMember).GetValue(component, null))[owner.Lang];
                }
     
                protected override Attribute[] AttributeArray
                {
                    get { return null; }
                    set { }
                }
                public override Type ComponentType
                {
                    get { return componentType; }
                }
                public override bool IsReadOnly
                {
                    get { return true; }
                }
                public override Type PropertyType
                {
                    get { return propertyType; }
                }
                public override bool CanResetValue(object component)
                {
                    return false;
                }
                public override void ResetValue(object component)
                {
                }
                public override void SetValue(object component, object value)
                {
                }
                public override bool ShouldSerializeValue(object component)
                {
                    return false;
                }
            }
    Et le binding se fait très simplement en intercalant mon LanguageBindingSource entre ma liste d'objet à binder et mon contrôle :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
                LanguageBindingSource<Product> lbs = new LanguageBindingSource<Product>();
                lbs.DataSource = products; //products est la liste de produit à binder. Sa propriété "Name" est un dictionnaire dont la clé est la langue et la valeur, le nom du produit traduit dans la bonne langue. 
                lbs.DataMember = "Name";
                lbs.Lang = Iso.fra;
     
                listBox1.DataSource = lbs;
    ****************************************

    - I don’t write plumbing code anymore
    - I use PostSharp
    - And you?


    ****************************************

Discussions similaires

  1. Réponses: 3
    Dernier message: 10/06/2009, 22h03
  2. Réponses: 3
    Dernier message: 31/10/2008, 14h17
  3. Définition d'une propriété de type 'TAnchors'
    Par Grosbenji dans le forum C++Builder
    Réponses: 3
    Dernier message: 08/02/2008, 10h14
  4. [nested] récupérer une propriété de type collection
    Par kokumbo dans le forum Struts 1
    Réponses: 2
    Dernier message: 25/10/2007, 16h16
  5. Réponses: 2
    Dernier message: 18/10/2003, 14h42

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