Gestion de sélections multiples avec MVVM
-
03-07-2019 - |
Question
Au cours de mon apprentissage de MVVM, j'ai acquis une compréhension de base de WPF et du modèle ViewModel. J'utilise l'abstraction suivante pour fournir une liste et je suis intéressé par un seul élément sélectionné.
public ObservableCollection<OrderViewModel> Orders { get; private set; }
public ICollectionView OrdersView
{
get
{
if( _ordersView == null )
_ordersView = CollectionViewSource.GetDefaultView( Orders );
return _ordersView;
}
}
private ICollectionView _ordersView;
public OrderViewModel CurrentOrder
{
get { return OrdersView.CurrentItem as OrderViewModel; }
set { OrdersView.MoveCurrentTo( value ); }
}
Je peux ensuite lier OrdersView avec la prise en charge du tri et du filtrage à une liste dans WPF:
<ListView ItemsSource="{Binding Path=OrdersView}"
IsSynchronizedWithCurrentItem="True">
Cela fonctionne très bien pour les vues à sélection unique. Mais je voudrais également prendre en charge plusieurs sélections dans la vue et faire en sorte que le modèle soit lié à la liste des éléments sélectionnés.
Comment lier ListView.SelectedItems à une propriété de support sur le ViewModel?
La solution
Ajoutez une propriété IsSelected
à votre enfant ViewModel ( OrderViewModel
dans votre cas):
public bool IsSelected { get; set; }
Liez la propriété sélectionnée du conteneur à ceci (pour ListBox dans ce cas):
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="IsSelected" Value="{Binding Mode=TwoWay, Path=IsSelected}"/>
</Style>
</ListBox.ItemContainerStyle>
IsSelected
est mis à jour pour correspondre au champ correspondant du conteneur.
Vous pouvez obtenir les enfants sélectionnés dans le modèle d'affichage en procédant comme suit:
public IEnumerable<OrderViewModel> SelectedOrders
{
get { return Orders.Where(o => o.IsSelected); }
}
Autres conseils
Je peux vous assurer que SelectedItems
peut effectivement être lié en tant que XAML CommandParameter
Il existe une solution simple à ce problème courant. pour que cela fonctionne, vous devez suivre TOUS les règles suivantes:
-
Après la suggestion d'Ed Ball , définissez le
CommandParameter
attribut AVANT l'attributCommande
. C’est un bug qui prend beaucoup de temps . -
Assurez-vous que vos méthodes
CanExecute
etExecute
deICommand
ont un paramètre de typeobjet
. . Ainsi, vous pouvez empêcher les exceptions silencieuses de se produire lorsque le typeCommandParameter
de la liaison de données ne correspond pas au type de paramètre de votre méthodeCommand
:private bool OnDeleteSelectedItemsCanExecute(object SelectedItems) { // Your code goes here } private bool OnDeleteSelectedItemsExecute(object SelectedItems) { // Your code goes here }
Par exemple, vous pouvez envoyer une propriété SelectedItems
de ListView
/ à ListBox
à vos méthodes ICommand
ou ListView
/ ListBox
lui-même. Génial, n'est-ce pas?
J'espère que cela empêchera quelqu'un de passer beaucoup de temps à comprendre comment recevoir SelectedItems
en tant que paramètre CanExecute
.
On peut essayer de créer une propriété attachée.
Cela vous évitera d’ajouter la propriété IsSelected
à chaque liste que vous liez. Je l’ai fait pour ListBox
, mais il peut être modifié pour être utilisé dans une vue en liste.
<ListBox SelectionMode="Multiple"
local:ListBoxMultipleSelection.SelectedItems="{Binding SelectedItems}" >
Plus d'infos: WPF - Liaison ListBox SelectedItems - Propriété jointe VS Style .
Si vous utilisez MVVM-LIGHT, vous pouvez utiliser ce modèle:
https: // galasoft .ch / posts / 2010/05 / processing-datagrid-selecteditems-in-an-mvvm-friendly-way
Pas particulièrement élégant, mais on dirait qu'il devrait être fiable au moins