Управление несколькими выборами с MVVM
На пути к изучению MVVM я приобрел некоторое базовое понимание WPF и шаблона ViewModel. Я использую следующую абстракцию при предоставлении списка и меня интересует один выбранный элемент.
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 ); }
}
Затем я могу связать OrdersView вместе с поддержкой сортировки и фильтрации в списке в WPF:
<ListView ItemsSource="{Binding Path=OrdersView}"
IsSynchronizedWithCurrentItem="True">
Это работает очень хорошо для одного выбора. Но я хотел бы также поддерживать несколько вариантов выбора в представлении и привязать модель к списку выбранных элементов.
Как бы я связал ListView.SelectedItems со свойством backer на ViewModel?
4 ответа
Добавить IsSelected
собственность для вашего ребенка ViewModel (OrderViewModel
в твоем случае):
public bool IsSelected { get; set; }
Привязать выбранное свойство в контейнере к этому (для ListBox в этом случае):
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="IsSelected" Value="{Binding Mode=TwoWay, Path=IsSelected}"/>
</Style>
</ListBox.ItemContainerStyle>
IsSelected
обновляется в соответствии с соответствующим полем на контейнере.
Вы можете получить выбранные дочерние элементы в модели представления, выполнив следующие действия:
public IEnumerable<OrderViewModel> SelectedOrders
{
get { return Orders.Where(o => o.IsSelected); }
}
Я могу заверить вас: SelectedItems
действительно связывается как XAML CommandParameter
Существует простое решение этой общей проблемы; чтобы это работало, вы должны следовать ВСЕМ следующим правилам:
Следуя совету Эда Болла, в привязке данных вашей команды XAML определите
CommandParameter
атрибут ДОCommand
приписывать. Это очень трудоемкая ошибка.Убедитесь, что ваш
ICommand
"sCanExecute
а такжеExecute
методы имеют параметр типаobject
, Таким образом, вы можете предотвратить исключения приведения с молчанием, возникающие всякий раз, когда привязка данныхCommandParameter
тип не соответствует вашемуCommand
Тип параметра метода:private bool OnDeleteSelectedItemsCanExecute(object SelectedItems) { // Your code goes here } private bool OnDeleteSelectedItemsExecute(object SelectedItems) { // Your code goes here }
Например, вы можете отправить ListView
/ListBox
"s SelectedItems
собственность на ваш ICommand
методы или ListView
/ListBox
сам. Отлично, не правда ли?
Я надеюсь, что это мешает кому-то тратить огромное количество времени, которое я потратил, чтобы выяснить, как получить SelectedItems
как CanExecute
параметр.
Можно попытаться создать прикрепленное свойство.
Это спасет от добавления IsSelected
свойство для каждого списка, который вы связываете. Я сделал это для ListBox
, но он может быть изменен для использования в виде списка.
<ListBox SelectionMode="Multiple"
local:ListBoxMultipleSelection.SelectedItems="{Binding SelectedItems}" >
Дополнительная информация: WPF - Binding ListBox SelectedItems - Присоединенное свойство VS Style.
Если вы используете MVVM-LIGHT, вы можете использовать этот шаблон:
https://galasoft.ch/posts/2010/05/handling-datagrid-selecteditems-in-an-mvvm-friendly-manner
Не особенно элегантно, но выглядит так, как минимум, должно быть надежно