Управление несколькими выборками с помощью MVVM
-
03-07-2019 - |
Вопрос
На моем пути к изучению 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?
Решение
Добавить 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
, но он может быть изменен для использования a в виде списка.
<ListBox SelectionMode="Multiple"
local:ListBoxMultipleSelection.SelectedItems="{Binding SelectedItems}" >
Подробная информация: WPF – Список привязки выбранных элементов – Присоединенное свойство В ЗАВИСИМОСТИ от стиля .
Если вы используете MVVM-LIGHT, вы можете использовать этот шаблон:
https://galasoft.ch/posts/2010/05/handling-datagrid-selecteditems-in-an-mvvm-friendly-manner
Не особенно элегантно, но выглядит так, что, по крайней мере, должно быть надежно