VirtualizingStackPanel + MVVM + multiple selection
I found another way of handling selection in the MVVM pattern, which solved my issue. Instead of maintaining the selection in the viewmodel, the selection is retrieved from the ListView/ListBox, and passed as a parameter to the Command. All done in XAML:
<ListView x:Name="_items" ItemsSource="{Binding Items}" ... /><Button Content="Remove Selected" Command="{Binding RemoveSelectedItemsCommand}" CommandParameter="{Binding ElementName=_items, Path=SelectedItems}"/>
in my ViewModel:
private void RemoveSelection(object parameter){ IList selection = (IList)parameter; ...}
In my case, I ended up solving this by deriving a ListBoxEx class from ListBox, and adding code to respond to selection changes, enforcing the selection state on the item view models:
private readonly List<IListItemViewModelBase> selectedItems = new List<IListItemViewModelBase>();protected override void OnSelectionChanged(SelectionChangedEventArgs e){ base.OnSelectionChanged(e); bool isVirtualizing = VirtualizingStackPanel.GetIsVirtualizing(this); bool isMultiSelect = (SelectionMode != SelectionMode.Single); if (isVirtualizing && isMultiSelect) { var newSelectedItems = SelectedItems.Cast<IListItemViewModelBase>(); foreach (var deselectedItem in this.selectedItems.Except(newSelectedItems)) { deselectedItem.IsSelected = false; } this.selectedItems.Clear(); this.selectedItems.AddRange(newSelectedItems); foreach (var newlySelectedItem in this.selectedItems) { newlySelectedItem.IsSelected = true; } }}
Apart from not using VirtualizingStackPanel
, the only thing I can think of is to capture those keyboard shortcuts and have methods for modifying a certain range of your ViewModel
items so that their IsSelected
property is set to True
(e.g., SelectAll()
, SelectFromCurrentToEnd()
). Basically bypassing the Binding
on ListViewItem
for controlling the selection for such cases.