2010-11-02 7 views
1

Après avoir lutté pendant environ une semaine avec un problème dans Silverlight 4 + MVVM-Light boîte à outils et après avoir cherché sur le web sans succès, je veux présenter mon problème ici et j'espère que quelqu'un pourrait donner moi quelques indices.Problème avec DataBinding une ComboBox dans Silverlight avec MVVM Light

Je veux présenter le Programme simplifié:

Mes classes de modèle:

  1. Personne

    public class Personne { décimal privé _cod_Person;

    public decimal Cod_Person 
    { 
        get { return _cod_Person; } 
        set { _cod_Person = value; } 
    } 
    private string _des_Person; 
    
    
    public string Des_Person 
    { 
        get { return _des_Person; } 
        set { _des_Person = value; } 
    } 
    

    }

  2. personinfo

    public class personinfo { décimal privé _cod_person;

    public decimal Cod_person 
    { 
        get { return _cod_person; } 
        set { _cod_person = value; } 
    } 
    private string _des_note; 
    
    
    public string Des_note 
    { 
        get { return _des_note; } 
        set { _des_note = value; } 
    } 
    

    }

Voici mon ViewModel:

public class PersonViewModel : ViewModelBase 
{ 
    public RelayCommand<Model.PersonInfo> save_Click { get; private set; } 

    public PersonViewModel() 
    { 
     save_Click = new RelayCommand<Model.PersonInfo>(personInfo => 
     { 
      SavePerson(personInfo); 
     }); 
     //the content of the combo box is defined 
     AllPerson = new ObservableCollection<Model.Person> 
     { 
      new Model.Person(){ 
       Cod_Person = 1, 
       Des_Person = "Name 1" 
      }, 
      new Model.Person(){ 
       Cod_Person = 2, 
       Des_Person = "Name 2" 
      } 
     }; 

     //an empty PersonInfo is created, which the UI will work on 
     ChoosenPerson = new Model.PersonInfo(); 
    } 

    private void SavePerson(Model.PersonInfo personInfo) 
    { 
     //here some safing processing could be done... 
     //but is omitted here 


     //and here a new PersonInfo is assigned the ChoosenPerson 
     ChoosenPerson = new Model.PersonInfo(); 
    } 

    public const string AllPersonPropertyName = "AllPerson"; 
    private ObservableCollection<Model.Person> _allPersons = null; 
    public ObservableCollection<Model.Person> AllPerson 
    { 
     get 
     { 
      return _allPersons; 
     } 

     set 
     { 
      if (_allPersons == value) 
      { 
       return; 
      } 

      var oldValue = _allPersons; 
      _allPersons = value; 
      RaisePropertyChanged(AllPersonPropertyName, oldValue, value, true); 
     } 
    } 

    public const string ChoosenPersonPropertyName = "ChoosenPerson"; 
    private Model.PersonInfo _choosenPerson = null; 
    public Model.PersonInfo ChoosenPerson 
    { 
     get 
     { 
      return _choosenPerson; 
     } 

     set 
     { 
      if (_choosenPerson == value) 
      { 
       return; 
      } 

      var oldValue = _choosenPerson; 
      _choosenPerson = value; 

      // Update bindings and broadcast change using GalaSoft.MvvmLight.Messenging 
      RaisePropertyChanged(ChoosenPersonPropertyName, oldValue, value, true); 
     } 
    } 
} 

À mon avis (PersonView) J'ai une zone de liste déroulante, une zone de texte et un bouton:

<UserControl x:Class="TEST_STACKOVERFLOW.PersonView" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     mc:Ignorable="d" 
     DataContext="{Binding Source={StaticResource Locator}, Path=PersonViewModel.ChoosenPerson}" d:DesignHeight="258" d:DesignWidth="341"> 
<Grid> 
    <ComboBox Height="23" HorizontalAlignment="Left" Margin="84,51,0,0" Name="comboBox1" VerticalAlignment="Top" Width="120" ItemsSource="{Binding Source={StaticResource Locator}, Path=PersonViewModel.AllPerson}" DisplayMemberPath="Des_Person" SelectedValuePath="Cod_Person" SelectedValue="{Binding Path=Cod_person, Mode=TwoWay}" /> 
    <Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="159,199,0,0" Name="button1" VerticalAlignment="Top" Width="75" Command="{Binding Source={StaticResource Locator}, Path=PersonViewModel.save_Click}" CommandParameter="{Binding}" /> 
    <TextBox Height="23" HorizontalAlignment="Left" Margin="94,107,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" Text="{Binding Path=Des_note, Mode=TwoWay}" /> 
</Grid> 

Lorsque le bouton est cliqué la première fois que tout fonctionne. Le paramètre (PersonInfo) passé après le clic sur le bouton contient la valeur ComboBox sélectionnée (Cod_person) et le texte inséré (Des_note). Dans la méthode SavePerson, une nouvelle instance PersonInfo est affectée à l'objet ChoosenPerson. Le problème se produit lorsque je clique sur le bouton une deuxième fois. Ensuite, en tant que paramètre après avoir cliqué sur le bouton, j'obtiens une instance de la classe PersonInfo qui contient le texte inséré correct dans la zone de texte mais comme valeur sélectionnée dans la liste déroulante, j'obtiens toujours , indépendamment de ce que j'ai choisi dans la zone de liste déroulante . Ce problème se produit juste dans le cas, que j'utilise en tant qu'instances d'éléments de zone de liste déroulante d'une classe. Si j'utilise comme éléments de liste déroulante uniquement des valeurs de chaîne, ce problème ne se produit pas. Mais je dois utiliser des instances d'une classe dans ma zone de liste déroulante.

J'espère que quelqu'un a un indice. Merci!

PS:

Intéressant est encore le fait que lors du changement de l'affectation du ChoosenPerson de "ChoosenPerson = new Model.PersonInfo();" à _choosenPerson = new Model.PersonInfo(); cela signifie par affectation par l'utilisation de membres privés au lieu de méthodes d'accès, la deuxième fois que le bouton est cliqué, les valeurs sont écrites dans le paramètre du bouton correctement. La seule chose est que les valeurs qui ont été insérées la dernière fois ne sont pas supprimées. Ils sont affichés après le premier clic sur le bouton. Mais ils ne sont pas affichés lorsque l'attribution d'un nouveau ChoosenPerson vide est faite par des méthodes d'accès ... Je ne peux pas expliquer ce comportement. Qui peut m'aider?? Je vous remercie.

Répondre

0

Adam était sur la bonne voie. J'attribuerais votre PersonViewModel au DataContext au lieu de l'affecter au ChoosenPerson.

<UserControl 
    x:Class="TEST_STACKOVERFLOW.PersonView" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    DataContext="{Binding Source={StaticResource Locator}, Path=PersonViewModel}" 
    mc:Ignorable="d" d:DesignHeight="258" d:DesignWidth="341"> 

    <Grid> 
     <ComboBox Height="23" HorizontalAlignment="Left" Margin="84,51,0,0" Name="comboBox1" VerticalAlignment="Top" Width="120" ItemsSource="{Binding AllPerson}" DisplayMemberPath="Des_Person" SelectedValuePath="Cod_Person" SelectedItem="{Binding Path=ChoosenPerson, Mode=TwoWay}" /> 
     <Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="159,199,0,0" Name="button1" VerticalAlignment="Top" Width="75" Command="{Binding save_Click}" CommandParameter="{Binding SelectedItem, ElementName=comboBox1}" /> 
     <TextBox Height="23" HorizontalAlignment="Left" Margin="94,107,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" Text="{Binding ChoosenPerson.Des_Person, Mode=TwoWay}" /> 
    </Grid> 
</UserControl> 

Je voudrais aussi se débarrasser totalement de la classe PersonInfo. Vous n'avez pas besoin de cette classe. Vous pouvez travailler directement avec l'objet Person. Changez vos références de PersonInfo à la classe Person. En outre, si vous souhaitez effacer la sélection en cours dans le ComboBox, définissez la propriété ChoosenPerson sur null. Ne pas créer de nouvelle instance d'une classe. La propriété ChoosenPerson doit être nulle ou l'un des objets de la collection AllPerson.

public class PersonViewModel : ViewModelBase 
{ 
    public RelayCommand<Person> save_Click { get; private set; } 

    public PersonViewModel() 
    { 
     save_Click = new RelayCommand<Person>(personInfo => 
     { 
      SavePerson(personInfo); 
     }); 

     //the content of the combo box is defined 
     AllPerson = new ObservableCollection<Person> 
     { 
      new Person(){ 
       Cod_Person = 1, 
       Des_Person = "Name 1" 
      }, 
      new Person(){ 
       Cod_Person = 2, 
       Des_Person = "Name 2" 
      } 
     }; 

     //an empty PersonInfo is created, which the UI will work on 
     ChoosenPerson = new Person(); 
    } 

    private void SavePerson(Person personInfo) 
    { 
     //here some safing processing could be done... 
     //but is omitted here 


     //and here a new PersonInfo is assigned the ChoosenPerson 
     ChoosenPerson = null; 
    } 

    public const string AllPersonPropertyName = "AllPerson"; 
    private ObservableCollection<Person> _allPersons = null; 
    public ObservableCollection<Person> AllPerson 
    { 
     get 
     { 
      return _allPersons; 
     } 

     set 
     { 
      if (_allPersons == value) 
      { 
       return; 
      } 

      var oldValue = _allPersons; 
      _allPersons = value; 
      RaisePropertyChanged(AllPersonPropertyName, oldValue, value, true); 
     } 
    } 

    public const string ChoosenPersonPropertyName = "ChoosenPerson"; 
    private Person _choosenPerson = null; 
    public Person ChoosenPerson 
    { 
     get 
     { 
      return _choosenPerson; 
     } 

     set 
     { 
      if (_choosenPerson == value) 
      { 
       return; 
      } 

      var oldValue = _choosenPerson; 
      _choosenPerson = value; 

      // Update bindings and broadcast change using GalaSoft.MvvmLight.Messenging 
      RaisePropertyChanged(ChoosenPersonPropertyName, oldValue, value, true); 
     } 
    } 
} 
+0

Merci Maintenant, tout fonctionne, le problème était en partie lié à DataBinding d'une part, et d'autre part à mes Classes, qui remplissaient le ComboBox doit implémenter l'interface IEquatable .... – WillCoer

0

Je pense que vous voulez quelque chose comme ceci:

<UserControl x:Class="TEST_STACKOVERFLOW.PersonView" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     mc:Ignorable="d" 
     DataContext="{Binding Source={StaticResource Locator}, Path=PersonViewModel}" d:DesignHeight="258" d:DesignWidth="341"> 
<Grid> 
    <ComboBox Height="23" HorizontalAlignment="Left" Margin="84,51,0,0" Name="comboBox1" VerticalAlignment="Top" Width="120" ItemsSource="{Binding AllPerson}" DisplayMemberPath="Des_Person" SelectedValuePath="Cod_Person" SelectedValue="{Binding Path=ChoosenPerson, Mode=TwoWay}" /> 
    <Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="159,199,0,0" Name="button1" VerticalAlignment="Top" Width="75" Command="{Binding save_Click}" CommandParameter="{Binding ChoosenPerson}" /> 
    <TextBox Height="23" HorizontalAlignment="Left" Margin="94,107,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" Text="{Binding Path=Des_note, Mode=TwoWay}" /> 
</Grid> 

Je mis à jour la plupart des liaisons. Une fois que vous avez défini le contexte de données UserControl, le reste des contrôles à l'intérieur peut simplement référencer le nom de la propriété, au lieu d'avoir à utiliser le localisateur. Je pense aussi que vous aviez quelques petites choses pointant vers les mauvais endroits.

+0

Cela ne fonctionne pas. Tout d'abord, la zone de texte est définie sur le chemin Des_note qui n'existe pas dans le jeu DataContext ci-dessus. Et deuxième La valeur SelectedValue de la zone de liste déroulante est définie sur le chemin ChoosenPerson qui a le type PersonInfo mais en tant que SelectedValuePath est défini Cod_Person qui a le type décimal. Le problème doit être autre chose. – WillCoer

+0

Je vois ça maintenant. Il semble que vous deviez modifier votre ViewModel pour suivre la personne actuelle, ainsi que le PersonInfo correspondant. Vous voulez vraiment définir DataContext UserControl à ViewModel lui-même - le point principal que j'essayais de faire dans ma réponse originale. Cela va vraiment simplifier les choses. Le ViewModel est un modèle de la vue - les propriétés et méthodes de celui-ci doivent correspondre assez étroitement aux contrôles de la vue. –

+0

OK, vous pensez à quelque chose comme ceci: ... DataContext = "{Source de liaison = {Locator StaticResource}, Path = PersonViewModel} ..