web-dev-qa-db-fra.com

Comment gérer l'événement SelectionChanged de ComboBox avec MVVM dans wpf?

Comment déclencher/gérer l'événement SelectionChanged du ComboBox de WPF à l'aide du modèle MVVM?
Expliquez en détail s'il vous plaît que je suis nouveau à WPF.

Ce que je veux, c’est faire quelques opérations lorsque la sélection de l’élément ComboBox a changé. Comment puis-je y arriver, d'une manière MVVM?

27
Tanya

Solution MVVM :

Liez les propriétés ItemsSource et SelectedItem de la ComboBox aux propriétés de votre ViewModel:

<ComboBox ItemsSource="{Binding MyItems}" SelectedItem="{Binding MySelectedItem}"/>

Dans MainViewModel.cs:

public ObservableCollection<string> MyItems { get; set; }

private string _mySelectedItem;
public string MySelectedItem
{
  get { return _mySelectedItem; }
  set
  {
    // Some logic here
    _mySelectedItem = value;
  }
}

Solution code-behind :

Si vous ne voulez pas utiliser MVVM, vous pouvez ajouter ceci:

 <ComboBox SelectionChanged="ComboBox_SelectionChanged" />

Et ajoutez ceci dans MainWindow.xaml.cs:

private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    // Some logic here
}
42
snurre

Je suis un grand fan de cette méthode.

xmlns:i="http://schemas.Microsoft.com/expression/2010/interactivity"

<ComboBox Grid.Column="2"  DisplayMemberPath="Data.name" ItemsSource="{Binding Model.Regions}" SelectedItem="{Binding Model.SelectedRegion}">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="SelectionChanged">
            <i:InvokeCommandAction Command="{Binding RegionChangedCmd}" />
        </i:EventTrigger>
    </i:Interaction.Triggers>
</ComboBox>
13
Blackey

Votre ViewModel doit implémenter INotifyPropertyChanged.

public class MyViewModel : INotifyPropertyChanged
{
    private string _mySelectedItem;
    public string MySelectedItem
    {
        get
        {
            return _mySelectedItem;
        }
        set
        {
            if (_mySelectedItem != value)
            {
                _mySelectedItem = value;
                // Perform any pre-notification process here.
                if (null != PropertyChanged)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs("MySelectedItem"));
                }
            }
        }
    } 
}

Le XAML précédemment posté est correct:

<ComboBox ItemsSource="{Binding MyItems}" SelectedItem="{Binding MySelectedItem}"/> 
6
Steven Licht

En premier lieu, clarifions les choses: vous ne pouvez pas changer d’événement, mais vous pouvez vous y abonner.

Étant donné que vous n'avez fourni aucune information concernant le lieu où vous souhaitez gérer les modifications de sélection, je supposerai le scénario le plus courant - la gestion dans le ViewModel sous-jacent. Selon MVVM, ViewModel ne doit rien savoir de View, vous ne pouvez donc pas vous abonner directement de ViewModel à l'événement d'un contrôle View. Mais vous pouvez lier une propriété de ViewModel à SelectedItem ou SelectedIndex afin qu'elle se déclenche lorsque la sélection change.

<ComboBox 
       SelectedIndex="{Binding SelectedIndexPropertyName}" 
       ... />

Il existe d'autres solutions permettant de manipuler le code derrière une vue en accédant à un ViewModel via view.DataContext, mais je suggérerais d'éviter cette pratique, car il s'agit de cas de contournement.

1
sll

Juste une amélioration de cette solution qui existe ci-dessus, si vous utilisez Prism Library 
(si non, alors arrêtez de lire maintenant, il n'y a rien pour vous)

J'aime beaucoup cette solution et je pense que c'est mieux que toute autre solution. Je souhaite simplement apporter une petite amélioration à cette solution fournie par la bibliothèque Prism. 

cette solution utilise 

<i:InvokeCommandAction Command="{Binding RegionChangedCmd}" />

remarquez le i: avant le InvokeCommandAction. Cela signifie que la classe InvokeCommandAction existe dans l’espace de nom xmlns:i="http://schemas.Microsoft.com/expression/2010/interactivity". C'est bien, mais notez que la bibliothèque Prism a exactement la même classe avec le même nom InvokeCommandAction. Il existe simplement dans un autre espace de noms, dans l'espace de noms xmlns:prism="http://prismlibrary.com/".

Donc, en réalité, vous pouvez remplacer le XAML suivant

<i:InvokeCommandAction Command="{Binding RegionChangedCmd}" />

avec ce XAML

<prism:InvokeCommandAction Command="{Binding RegionChangedCmd}" />

OK, on ​​peut faire ça, quel est l'avantage? 
Pour constater l’avantage, écrivez la commande suivante dans le ViewModel

public ICommand RegionChangedCmd { get; }

public ViewModelConstructor() 
{
   RegionChangedCmd = new DelegateCommand<SelectionChangedEventArgs>(RegionChangedCmdExecuted);
}

public void RegionChangedCmdExecuted(SelectionChangedEventArgs e)
{
   // e parameter is null     if you use <i:InvokeCommandAction>
   // e parameter is NOT null if you use <prism:InvokeCommandAction>
}

le paramètre est null si vous utilisez <i:InvokeCommandAction> 
Le paramètre e est NOT null si vous utilisez <prism:InvokeCommandAction>

0
Hakam Fostok