46 votes

WPF MVVM ComboBox SelectedItem ou SelectedValue ne fonctionne pas

Mise à jour

Après quelques recherches. Ce qui semble être le problème, c'est que la SelectedValue/SelectedItem se produit avant que la source de l'élément n'ait fini de se charger. Si je m'assois à un point d'arrêt et que j'attends quelques secondes, cela fonctionne comme prévu. Je ne sais pas comment je vais résoudre ce problème.

Fin de la mise à jour

J'ai une application en WPF utilisant MVVM avec une ComboBox. Ci-dessous se trouve l'exemple du ViewModel. Le problème que je rencontre est que lorsque nous quittons notre page et que nous revenons, la ComboBox ne sélectionne pas la valeur courante qui est sélectionnée.

Voir le modèle

public class MyViewModel
{
     private MyObject _selectedObject;
     private Collection<Object2> _objects;
     private IModel _model;

     public MyViewModel(IModel model)
    {
         _model = model;
         _objects = _model.GetObjects();
    }

    public Collection<MyObject> Objects
    {
         get
         {
              return _objects;
         }
         private set
         {
              _objects = value;
         }
     }

     public MyObject SelectedObject
     {
          get
          {
              return _selectedObject;
          }
          set
          {
               _selectedObject = value;
          }
      }
 }

Pour les besoins de cet exemple, disons que MyObject possède deux propriétés (Text et Id). Mon XAML pour la ComboBox ressemble à ceci.

XAML

<ComboBox Name="MyComboBox" Height="23"  Width="auto" 
    SelectedItem="{Binding Path=SelectedObject,Mode=TwoWay}" 
    ItemsSource="{Binding Objects}"
    DisplayMemberPath="Text"
    SelectedValuePath="Id">

Quelle que soit ma configuration, lorsque je reviens sur la page et que l'objet est réassemblé, la ComboBox ne sélectionne pas la valeur. L'objet renvoie pourtant le bon objet via le get dans la propriété.

Je ne suis pas sûr qu'il s'agisse d'un problème lié au fonctionnement de la ComboBox et du modèle MVVM. La liaison avec la zone de texte que nous effectuons fonctionne correctement.

48voto

rp7799 Points 116

Paramètres IsSynchronizedWithCurrentItem="True" a fonctionné pour moi !

1 votes

Merci Wim. Cela fait 40 minutes que je me bats avec cette question.

2 votes

J'ai eu des difficultés à ce sujet. Ceci a parfaitement fonctionné pour moi. Merci :)

1 votes

J'ai pris beaucoup trop de temps pour ce petit problème, mais cela a fonctionné pour moi ! Merci beaucoup !

27voto

Orion Edwards Points 54939

Avez-vous essayé de mettre en œuvre INotifyPropertyChanged dans votre modèle de vue, puis levez l'option PropertyChanged lorsque l'événement SelectedItem se met en place ?

Si cela ne suffit pas à résoudre le problème, vous pourrez alors relever manuellement le niveau du PropertyChanged lorsque vous retournez sur la page, et cela devrait suffire pour que WPF se redessine et affiche le bon élément sélectionné.

0 votes

Notre implémentation actuelle hérite d'une classe ViewBase qui implémente INotifyPropertyChanged. Je déclenche le PropertyChange mais la liste déroulante reste vide.

0 votes

Mieux encore, si je mets des points d'arrêt et que j'attends un peu, cela fonctionne. Je pense que mon selecteditem est mis en place avant que le binding de la combobox ne soit fait. Urgh.

1 votes

J'ai oublié de déclencher l'événement PorpertyChanged lors de la navigation vers la page.

23voto

GuestPerson Points 81

Vous devez placer la propriété ItemsSource AVANT la propriété SelectedItem. Je suis tombé sur un blog il y a quelques jours qui mentionnait ce problème.

0 votes

Je m'arrachais les cheveux en essayant de comprendre ce que je faisais de mal avec mon XAML ou mon modèle de vue, alors que c'était cela depuis le début.

0 votes

Bosh, excellente réponse !

0 votes

Ne fonctionne pas sur VS 15.8.1, la réponse de @rp7799 est parfaite.

12voto

Breno P. Lucena Points 41

Dans ce cas, la liaison selecteditem ne fonctionne pas, car l'identifiant de hachage des objets est différent.

Une solution possible est la suivante :

Sur la base de l'identifiant de l'élément sélectionné, récupérez l'objet dans la collection itemsource et définissez la propriété de l'élément sélectionné avec cet objet.

Exemple :

<ctrls:ComboBoxControlBase SelectedItem="{Binding Path=SelectedProfile, Mode=TwoWay}" ItemsSource="{Binding Path=Profiles, Mode=OneWay}" IsEditable="False" DisplayMemberPath="Name" />

La propriété liée à ItemSource est :

public ObservableCollection<Profile> Profiles
{
   get { return this.profiles; }
   private set { profiles = value; RaisePropertyChanged("Profiles"); }
}

La propriété liée à SelectedItem est :

public Profile SelectedProfile 
{
    get { return selectedProfile; }
    set
    {
        if (this.SelectedUser != null)
        {
            this.SelectedUser.Profile = value; 
            RaisePropertyChanged("SelectedProfile");  
        } 
    } 
}

Le code de recouvrement est le suivant :

    [Command("SelectionChanged")]
    public void SelectionChanged(User selectedUser)
    {
        if (selectedUser != null)
        {
            if (selectedUser is User)
            {
                if (selectedUser.Profile != null)
                {
                    this.SelectedUser = selectedUser;
                    this.selectedProfile = this.Profiles.Where(p => p.Id == this.SelectedUser.Profile.Id).FirstOrDefault();
                    MessageBroker.Instance.NotifyColleagues("ShowItemDetails"); 
                }
            }
        }            
    }

J'espère que cela vous aidera. J'ai passé beaucoup de temps à chercher des réponses, mais je n'en ai pas trouvé.

11voto

J'ai eu des problèmes similaires et je les ai résolus en m'assurant que je mettais en œuvre les mesures suivantes IEquatable correctement. Lorsque la liaison se produit, elle essaie de voir si les objets correspondent ; assurez-vous donc que vous implémentez correctement votre vérification de l'égalité.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X