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 xaml sur une List/ObserveableCollection du Model plutôt que sur une propriété du Model


Sujet :

Windows Presentation Foundation

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    32
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 32
    Points : 17
    Points
    17
    Par défaut Binding xaml sur une List/ObserveableCollection du Model plutôt que sur une propriété du Model
    Bonjour, j'ai un petit soucis de prise en compte d'un binding non pas sur une simple propriété de mon modèle mais sur une liste d'objets.

    L'énoncé est le suivant, (ça risque d'être long... ) :

    ps : Génial, je viens de virer tout ce que j'ai écrit depuis 10 minutes en faisant un malencontreux ctrl+w ......

    Bon c'est reparti :
    Donc on va dire (pour simplifier) que mes objets c'est des formule 1, chaque F1 a deux propriété : couleur et vitesse max.

    Dans mon model, j'ai une liste de F1 (List<F1>) appelée ListeF1 (10 F1 précisément dans la liste) (la classe F1 est INotifyPr... avec les setter correctement complétés).

    Dans ma vue, j'ai 10 UserControl qui détaille une F1 à la fois, c'est bindé dans le xaml de la manière suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    ...
    Couleur="{Binding Model.ListeF1[0].Couleur}"
    VMax="{Binding Model.ListeF1[0].VMax}"
    ...
    Dans le ViewModel dans ma méthode actualiser, je met à jour la List<F1> (les F1 sont toujours les même,on garde 10 objets, on ne doit pas en ajouter ou en supprimer, je met juste à jour les propriétés des F1) de mon modèle et ça répercute automatiquement les changements sur les propriétés de chaque F1 dans les Control de la vue (grâce au fait que F1 soit INoti...).

    Pour que ça marche, dans le UserControl, on utilise une dependency property pour enregistrer chaque propriété et récupérer les notif des mise à jour :
    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
    #region Couleur
    public ushort Couleur
    {
    	get
    	{
    		return (ushort)GetValue(CouleurProperty);
    	}
    	set
    	{
    		SetValue(CouleurProperty, value);
    	}
    }
     
    public static readonly DependencyProperty CouleurProperty =
       DependencyProperty.Register(
    	  "Couleur",
    	  typeof(ushort),
    	  typeof(UcMiseEnOeuvreMono),
    	  new FrameworkPropertyMetadata(
    		 new PropertyChangedCallback(ChangeCouleur)));
     
    private static void ChangeCouleur(DependencyObject source, DependencyPropertyChangedEventArgs e)
    {
    	(source as UcMiseEnOeuvreMono).UpdateCouleur((ushort)e.NewValue);
    }
     
    private void UpdateCouleur(ushort Couleur)
    {
    	ucMiseEnOeuvreDepart.Couleur = Couleur;
    }
    #endregion

    On arrive au soucis, j'ai un autre UserControl qui permet de gérer les 10 F1 d'un coup. Et donc au binding, je ne souhaite pas binder chaque propriété de chaque F1 dans le xaml et donc me retaper les dependency property * le nombre de f1 * le nombre de propriétés dans le code behind de l'user control.

    L'idée c'est donc de binder dans le xaml ma liste elle même :
    Code c# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    ...
    ListeF1="{Binding Model.ListeF1}"
    ...
    Je créé donc une dependency property dans le .cs de l'userControl sur la liste de F1.

    En démarrant mon application je constate que le nouvel userControl s'affiche correctement la première fois que je l'affiche, mais ensuite toute mise à jour sur l'une des F1 n'est pas répercutée sur ma vue comme c'est le cas des autres contrôles (mono F1) .

    J'ai transformé la liste en une ObservableCollection et je me suis rendu compte que les modifications sur les propriétés des éléments ne sont pas notifiés, alors j'ai essayé de les notifier en accrochant un PropertyChanged sur chaque F1 pour déclencher un RaisePropertyChanged mais rien n'y fait le binding dans le xaml marche juste la 1ère fois et ensuite il ne se met pas à jour même en faisant un RaisePropertyChanged sur la liste de F1.

    nb : par RaiseProperty j'entend :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    NotifyPropertyChanged("ListeF1");
    avec la méthode :
    Code c# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    private void NotifyPropertyChanged(String info)
    {
    	if (PropertyChanged != null)
    	{
    		PropertyChanged(this, new PropertyChangedEventArgs(info));
    	}
    }
    sachant que le binding dans le xaml est celui ci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    ...
    ListeF1="{Binding Model.ListeF1}"
    ...
    et que la dependencyProperty dans le .cs du contrôle est enregistrée sur "ListeF1" :
    Code c# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    public static readonly DependencyProperty DepartsProperty =
    DependencyProperty.Register(
      "ListeF1",
      typeof(List<Uti.F1>),
      typeof(UcMiseEnOeuvreGlobale),
      new FrameworkPropertyMetadata(
    	 new PropertyChangedCallback(ChangeDeparts)));


    Vous connaissez la/une solution ou vous en avez une meilleure ?
    Merci d'avance.

  2. #2
    Membre expert
    Avatar de GuruuMeditation
    Homme Profil pro
    .Net Architect
    Inscrit en
    Octobre 2010
    Messages
    1 705
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : Belgique

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

    Informations forums :
    Inscription : Octobre 2010
    Messages : 1 705
    Points : 3 568
    Points
    3 568
    Par défaut
    Tu es dans quel version du framework ?

    Tu ne dois pas faire un OnNotifyPropertyChange sur la collection elle-meme, parce que l’objet collection en lui même ne change pas.

    J'ai fait un petit exemple qui marche (.NET 4.5.):

    le code C# :
    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
     
      public ObservableCollection<DummyType2> ObservableCollection2 { get; set; }
     
     public MainWindow()
            {
                InitializeComponent();
     
                ObservableCollection2 = new ObservableCollection<DummyType2> { new DummyType2 { TheText = "Text1" }, new DummyType2 { TheText = "Text2" }, new DummyType2 { TheText = "Text3" } };
     
     
     
     
                this.DataContext = this;
     
            }
     
            private void Button_Click_1(object sender, RoutedEventArgs e)
            {
                ObservableCollection2[0].TheText = "New Text!!!";
     
            }

    Le type DummyType2 :
    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
     
    public class DummyType2 : UserControl
        {
            public string TheText
            {
                get
                {
                    return (string)GetValue(CouleurProperty);
                }
                set
                {
                    SetValue(CouleurProperty, value);
                }
            }
     
            public static readonly DependencyProperty CouleurProperty =
            DependencyProperty.Register(
            "TheText",
            typeof(string),
            typeof(UserControl),
            null);
     
     
        }

    Le XAML :
    Code XAML : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
     <StackPanel Orientation="Vertical">
                <ListView ItemsSource="{Binding ObservableCollection2}">
                    <ListView.ItemTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding TheText}"></TextBlock>
                        </DataTemplate>
                    </ListView.ItemTemplate>
                </ListView>
                <Button Content="Click" Click="Button_Click_1"></Button>
     
            </StackPanel>

  3. #3
    Membre à l'essai
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    32
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 32
    Points : 17
    Points
    17
    Par défaut
    Bonjour, merci pour la réponse, je suis sur du Framework 4.
    Je viens d'améliorer mon approche dans mon projet et j'ai du mieux mais le PropertyChanged sur les propriétés des mes F1 ne marche pas encore totalement :


    Nouvelle version :
    J'ai une vue et 3 UC.

    Le 1er UC est l'UCdétailF1, il affiche le contenu des propriétés de la F1 et c'est lui qui enregistre les DP. (Comme DummyType2)

    Le 2ème UC contient un UCdétailF1, il s'appelle UCmono.
    Le 3ème UC contient plusiers UCdétailF1, il s'appelle UCglobale.

    Dans l'UCmono, je bind dans le xaml les propriétés de la F1 liée.
    Code xaml : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    <local:UcDetailF1 x:Name="ucMeoD1"
    	Couleur="{Binding Model.ListeF1[0].Couleur}" 
    	CodeEmplacement="{Binding Model.ListeF1[0].VMax}"/>

    Dans l'UCglobal, je bind dans le xaml les propriétés de chacune des F1 liées.
    Code xaml : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    <local:UcDetailF1 x:Name="ucMeoD1"
    	Couleur="{Binding Model.ListeF1[0].Couleur}" 
    	CodeEmplacement="{Binding Model.ListeF1[0].VMax}"/>
    <local:UcDetailF1 x:Name="ucMeoD2"
    	Couleur="{Binding Model.ListeF1[1].Couleur}" 
    	CodeEmplacement="{Binding Model.ListeF1[1].VMax}"/>
    <local:UcDetailF1 x:Name="ucMeoD3"
    	Couleur="{Binding Model.ListeF1[2].Couleur}" 
    	CodeEmplacement="{Binding Model.ListeF1[2].VMax}"/>

    On remarquera que dans les deux UC (mono et global), je bind dans le xaml directement sur la liste de F1 (des objets pas des UC) du Model.
    Donc je bind sur un objets que l'on bind habituellement dans la vue et pas dans un des UC de la vue.

    Avec cette méthode, le propertyChanged marche sur les propriétés de mes F1 quand une propriété passe de :
    null à une valeur
    ou d'une valeur à null
    mais pas d'une valeur à une autre valeur.

    Comment peut on faire en sorte que ça marche de manière élégante ?

  4. #4
    Membre à l'essai
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    32
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 32
    Points : 17
    Points
    17
    Par défaut
    Ayé ça marche !!! !

    Par contre, je suis pas trop sûr de comprendre ce que je faisais :
    Dans les register sur les DP dans l'UCdetail :

    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
    #region Couleur
    public byte Couleur
    {
    	get
    	{
    		return (byte)GetValue(CouleurProperty);
    	}
    	set
    	{
    		SetValue(CouleurProperty, value);
    	}
    }
     
    public static readonly DependencyProperty CouleurProperty =
       DependencyProperty.Register(
    	  "Couleur",
    	  typeof(byte),
    	  typeof(UcMiseEnOeuvreDepart),
    	  new FrameworkPropertyMetadata(
    		 new PropertyChangedCallback(ChangeCouleur)));
     
    private static void ChangeCouleur(DependencyObject source, DependencyPropertyChangedEventArgs e)
    {
    	(source as UcMiseEnOeuvreDepart).UpdateCouleur((byte)e.NewValue);
    }
     
    private void UpdateCouleur(byte couleur)
    {
    	Couleur = couleur;
    	ActualiserAffichageControle();
    }
    #endregion

    C'est ici que je faisais une mauvaise manip :
    Code c# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    private void UpdateCouleur(byte couleur)
    {
    	Couleur = couleur;
    	ActualiserAffichageControle();
    }

    En enlevant le Couleur = couleur; tout marche nickel .

    Par contre, je vois pas trop ce que ça faisait,
    je tuais la DP en l'affectant à une variable locale ?

  5. #5
    Membre expert
    Avatar de GuruuMeditation
    Homme Profil pro
    .Net Architect
    Inscrit en
    Octobre 2010
    Messages
    1 705
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : Belgique

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

    Informations forums :
    Inscription : Octobre 2010
    Messages : 1 705
    Points : 3 568
    Points
    3 568
    Par défaut
    Bizarre, a première vue, ça ne devrait pas influencer.

    Bon, vaut mieux ne pas savoir pourquoi ça marche plutôt que savoir pourquoi ça ne marche pas

Discussions similaires

  1. [Toutes versions] Comment travailler sur des données stockées en mémoire, plutôt que sur une feuille
    Par wyzer dans le forum Macros et VBA Excel
    Réponses: 4
    Dernier message: 19/04/2011, 13h35
  2. Réponses: 3
    Dernier message: 15/02/2011, 17h17
  3. inserer une liste de personne dans un champ d'une liste
    Par must19 dans le forum SharePoint
    Réponses: 1
    Dernier message: 02/09/2008, 10h12
  4. Réponses: 1
    Dernier message: 30/06/2008, 12h55
  5. Réponses: 7
    Dernier message: 28/06/2007, 11h08

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