Au cours de mon parcours d'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 de sélection unique. Mais j'aimerais également prendre en charge plusieurs sélections dans la vue et que le modèle soit lié à la liste des éléments sélectionnés.
Comment lierais-je ListView.SelectedItems à une propriété de backer sur ViewModel?
Ajoutez une propriété IsSelected
à votre ViewModel enfant (OrderViewModel
dans votre cas):
public bool IsSelected { get; set; }
Liez la propriété sélectionnée sur le 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 sur le conteneur.
Vous pouvez obtenir les enfants sélectionnés dans le modèle de vue en procédant comme suit:
public IEnumerable<OrderViewModel> SelectedOrders
{
get { return Orders.Where(o => o.IsSelected); }
}
Je peux vous assurer: SelectedItems
est en effet contraignable en XAML CommandParameter
Il existe une solution simple à ce problème courant; pour le faire fonctionner, vous devez suivre [~ # ~] tous [~ # ~] les règles suivantes:
Après suggestion d'Ed Ball , sur votre liaison de données de commande XAML, définissez l'attribut CommandParameter
[~ # ~] avant [~ # ~] l'attribut Command
. C'est un bug qui prend beaucoup de temps.
Assurez-vous que vos méthodes ICommand
CanExecute
et Execute
ont un paramètre de type object
. De cette façon, vous pouvez empêcher les exceptions de cast - silenced qui se produisent chaque fois que le type CommandParameter
de la liaison de données ne correspond pas au type de paramètre de votre méthode Command
:
private bool OnDeleteSelectedItemsCanExecute(object SelectedItems)
{
// Your code goes here
}
private bool OnDeleteSelectedItemsExecute(object SelectedItems)
{
// Your code goes here
}
Par exemple, vous pouvez envoyer la propriété ListView
de ListBox
/SelectedItems
à vos méthodes ICommand
ou les ListView
/ListBox
lui-même. Super, non?
J'espère que cela empêche quelqu'un de passer le temps énorme que j'ai fait pour 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
pour chaque liste que vous liez. Je l'ai fait pour ListBox
, mais il peut être modifié pour être utilisé dans une vue de liste.
<ListBox SelectionMode="Multiple"
local:ListBoxMultipleSelection.SelectedItems="{Binding SelectedItems}" >
Plus d'informations: WPF - Binding ListBox SelectedItems - Attached Property VS Style .
Si vous utilisez MVVM-LIGHT, vous pouvez utiliser ce modèle:
https://galasoft.ch/posts/2010/05/handling-datagrid-selecteditems-in-an-mvvm-friendly-manner
Pas particulièrement élégant, mais il semble qu'il devrait être fiable au moins