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.

4voto

Dave Points 31

Lorsque l'on quitte la page en cours, la fonction CollectionView associée à la ItemsSource de la propriété ComboBox est purgé. Et parce que le ComboBox IsSyncronizedWithCurrent est vraie par défaut, la propriété SelectedItem et SelectedValue sont réinitialisées.
Il semble qu'il s'agisse d'un problème de type de données interne dans la liaison. Comme d'autres l'ont suggéré plus haut, si vous utilisez SelectedValue à la place en liant à une propriété int sur le viewmodel, cela fonctionnera. Un raccourci pour vous serait de surcharger la propriété Equals sur MyObject afin que, lors de la comparaison de deux MyObjects, l'opérateur Id sont comparées.

Autre conseil : si vous restructurez vos modèles de vue et que vous utilisez des SelectedValue Le système ne doit être utilisé que dans les cas suivants SelectedValuePath=IdId est int . En cas d'utilisation d'une clé de type chaîne, lier à l'élément Text de la propriété ComboBox au lieu de SelectedValue .

4voto

JCH2k Points 170

J'ai rencontré ce problème avec une ComboBox affichant une liste de couleurs ( List<Brush> ).
La sélection d'une couleur était possible mais elle n'était pas affichée lorsque la sélection se fermait (bien que la propriété ait été modifiée !).

La solution consistait à écraser la méthode Equals(object obj) pour le type sélectionné dans la ComboBox (Brush), ce qui n'était pas simple car Brush est scellé. J'ai donc écrit une classe EqualityBrush contenant un pinceau et implémentant le principe Equals :

public class EqualityBrush
{
    public SolidColorBrush Brush { get; set; }

    public override bool Equals(object o)
    {
        if (o is EqualityBrush)
        {
            SolidColorBrush b = ((EqualityBrush)o).Brush;
            return b.Color.R == this.Brush.Color.R && b.Color.G == this.Brush.Color.G && b.Color.B == this.Brush.Color.B;
        }
        else
            return false;
    }
}

L'utilisation d'une liste de ma nouvelle classe EqualityBrush au lieu de la classe Brush normale a résolu le problème !

Mon Combobox XAML ressemble à ceci :

<ComboBox ItemsSource="{Binding BuerkertBrushes}" SelectedItem="{Binding Brush, Mode=TwoWay}" Width="40">
    <ComboBox.Resources>
        <DataTemplate DataType="{x:Type tree:EqualityBrush}">
            <Rectangle Width="20" Height="12" Fill="{Binding Brush}"/>
        </DataTemplate>
    </ComboBox.Resources>
</ComboBox>

Rappelez-vous que ma propriété "Brush" dans le fichier Modèle de vue doit maintenant être de type EqualityBrush !

3voto

Abe Heidebrecht Points 16417

J'ai déjà remarqué ce comportement auparavant. J'ai remarqué que la propriété SelectedIndex ne provoque pas le même problème. Si vous pouvez restructurer votre ViewModel pour exposer l'index de l'élément sélectionné, et vous lier à cela, vous devriez être en mesure de le faire.

3voto

Peter T. Points 321

J'ai résolu le problème en ajoutant un distributeur dans l'événement UserControl_Loaded

 Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new Action(() =>
 {
     combobox.SelectedIndex = 0;
 }));

2voto

StefanHa Points 328

J'ai eu le même problème. Le problème est le suivant. L'élément sélectionné ne sait pas quel objet de la collection il doit utiliser. Il faut donc dire à l'élément sélectionné d'utiliser l'objet de la collection.

public MyObject SelectedObject
 {
      get
      {
          Objects.find(x => x.id == _selectedObject.id)
          return _selectedObject;
      }
      set
      {
           _selectedObject = value;
      }
 }

J'espère que cela vous aidera.

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