2011-01-07 3 views
1

J'utilise le modèle MVVM pour créer une application. Dans cette application, j'ai un ComboBox qui est lié à un colletion d'articles et à une propriété contenant l'élément sélectionné:WPF: Réinitialisation d'une zone de liste déroulante après modification

<ComboBox ItemsSource="{Binding Path=Persons, Mode=OneTime}" 
      SelectedValue="{Binding Path=SelectedPerson, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/> 

La collection avec les éléments de cette zone de liste déroulante est initialisé avec un « texte d'instruction » comme le premier élément, puis un tas d'objets ordinaires:

Persons.Add("Open Person..."); 
Persons.Add("Anders Andersson"); 
Persons.Add("Bengt Bengtsson"); 
Persons.Add("Carl Carlsson"); 
Persons.Add("Daniel Danielsson"); 

le comportement que je voudrais avoir pour cette ComboBox est qu'il montre d'abord le texte d'instructions (ce qui est bien sûr facile à réaliser). Lorsque l'utilisateur sélectionne une personne dans la zone de liste déroulante, l'application effectue une action (ouvre la personne sélectionnée) et la réinitialise ensuite au texte d'instruction.

Comme d'abord pensé que ce serait facile en ayant cette propriété pour l'élément sélectionné:

private string _selectedPerson = "Open Person..."; 
public string SelectedPerson 
{ 
    get 
    { 
     return _selectedPerson; 
    } 
    set 
    { 
     if (value != _selectedPerson) 
     { 
      OpenPerson(value); 
      OnPropertyChanged("SelectedPerson"); 
     } 
    } 
} 

Mon idée était que lorsque l'utilisateur sélectionne autre chose que le texte d'instructions dans la zone de liste déroulante, OpenPerson() sera appelé avec la valeur sélectionnée, mais la valeur sélectionnée ne sera pas stockée dans le champ privé (_selectedPerson). Ensuite, je déclenche l'événement PropertyChanged qui fera lire la valeur ComboBox de la propriété SelectedPerson et se mettre à jour (SelectedValue). Parce que le champ _seletedPerson est toujours le texte d'instruction, le ComboBox se réinitialisera à cela.

Cela ne fonctionne PAS.

En fait, tout semble se passer comme prévu. OpenPerson() est appelé avec le bon paramètre, puis l'événement PropertyChanged est déclenché. Cependant, l'action de l'interface graphique pour changer la valeur affichée par la ComboBox est effectivement effectuée après tout cela. Cela signifie que, quelle que soit la valeur de SelectedPerson, le composant ComboBox affiche l'élément sélectionné dans l'interface graphique.

Existe-t-il un moyen élégant de contourner ce problème?

En fait, je me suis débrouillé tout seul. Mais cela impliquait du code dans CodeBehind, deux drapeaux dans le ViewModel et du code méchant dans la propriété SelectedPerson. La solution n'est pas satisfaisante pour le moins ...;) Donc, j'espérais que quelqu'un de plus intelligent que moi pourrait trouver une meilleure solution! :)

Répondre

1

Avez-vous essayé de créer un gestionnaire SelectionChanged pour la zone de liste déroulante et de revenir à "Open Person ..." à la place?

Ou même un déclencheur pour la zone de liste déroulante qui le place à Index = 0 ou quelque chose?

+0

Bien sûr! L'utilisation d'un gestionnaire SelectionChanged est la solution la plus simple. Je pensais tellement à la façon de faire cela dans le ViewModel que je n'ai jamais pensé à ça. Bien sûr, je préférerais que ma solution ci-dessus fonctionne, donc je n'aurais pas besoin de code dans mon code, mais évidemment ce n'est pas le cas. Merci Ingó! :) – haagel

0

Je viens de trouver cette recherche d'autre chose, j'espère que je peux encore aider.

Je lie une commande à l'événement selectionchanged, cette commande est définie dans le Viewmodel et suit donc le modèle MVVM (aucun code derrière).

J'utilise le cadre MVVM Light de sorte que vous devez inclure les éléments suivants qui comprend une référence d'interactivité de mélange:

xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" 
xmlns:cmd="http://www.galasoft.ch/mvvmlight" 

ce qui suit est ce que je déclare dans mon XAML:

  <ComboBox Name="idClient" Grid.Column="1" Grid.ColumnSpan="2" Grid.Row="2" 
           Style="{StaticResource FTC_DetailComboBox}" 
           ItemsSource="{Binding ClientViewSource.View}" 
           SelectedItem="{Binding client}" 
           SelectedValuePath="idClient" 
           SelectedValue="{Binding idClient, Mode=TwoWay, ValidatesOnDataErrors=True}" 
           DisplayMemberPath="chrCompany" 
           > 
       <i:Interaction.Triggers> 
        <i:EventTrigger EventName="SelectionChanged"> 
         <cmd:EventToCommand Command="{Binding LostFocusValidateCommand}" CommandParameter="idStatus"/> 
        </i:EventTrigger> 
       </i:Interaction.Triggers> 
      </ComboBox> 

Voici le code de mon viewmodel (en vb.net).RelayCommand est une implémentation simple de ICommand

Private _LostFocusValidateCommand As RelayCommand(Of String) 

    Public ReadOnly Property LostFocusValidateCommand() As RelayCommand(Of String) 
     Get 
      If _LostFocusValidateCommand Is Nothing Then 
       _LostFocusValidateCommand = New RelayCommand(Of String)(AddressOf LostFocusValidateExecute) 
      End If 
      Return _LostFocusValidateCommand 
     End Get 
    End Property 

    Private Sub LostFocusValidateExecute(sParam As String) 
     ''perform commands here 
    End Sub 
Questions connexes