wpf listview mvvm stackpanel virtualizingstackpanel

wpf - VirtualizingStackPanel+MVVM+selección múltiple



listview (3)

Además de no usar VirtualizingStackPanel , lo único que se me ocurre es capturar esos accesos directos de teclado y tener métodos para modificar un cierto rango de los elementos de ViewModel para que su propiedad IsSelected se establezca en True (por ejemplo, SelectAll() , SelectFromCurrentToEnd() ) Básicamente omitiendo el Binding en ListViewItem para controlar la selección para tales casos.

Implementé un patrón de selección similar al descrito en esta publicación utilizando un ViewModel para almacenar el valor IsSelected, y vinculando el ListViewItem.IsSelected al ViewModel IsSelected:

<ListView.ItemContainerStyle> <Style TargetType="{x:Type ListViewItem}"> <Setter Property="IsSelected" Value="{Binding Mode=TwoWay, Path=IsSelected}"/> </Style> </ListView.ItemContainerStyle>

Funciona en general, pero encuentro un problema grave. Al utilizar VirtualizingStackPanel como panel en la vista de lista, solo se está creando el ListViewItem visible. Si utilizo "Ctrl + A" para seleccionar todos los elementos o si utilizo una combinación de atajos como "Mayús + Ctrl + Fin" en el primer elemento, todos los elementos se seleccionan, pero para los elementos no visibles, ViewModel no obtiene su nombre. establecido en verdadero. Eso es lógico, porque si ListViewItem no se crea, el enlace no puede funcionar.

¿Alguien experimentó el mismo problema y encontró una solución (aparte de no usar VirtualizingStackPanel )?


En mi caso, terminé resolviendo esto derivando una clase ListBoxEx de ListBox y agregando código para responder a los cambios de selección, imponiendo el estado de selección en los modelos de vista de elementos:

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; } } }


Encontré otra forma de manejar la selección en el patrón MVVM, que resolvió mi problema. En lugar de mantener la selección en el modelo de vista, la selección se recupera de ListView / ListBox y se pasa como un parámetro al comando. Todo hecho en XAML:

<ListView x:Name="_items" ItemsSource="{Binding Items}" ... /> <Button Content="Remove Selected" Command="{Binding RemoveSelectedItemsCommand}" CommandParameter="{Binding ElementName=_items, Path=SelectedItems}"/>

en mi ViewModel:

private void RemoveSelection(object parameter) { IList selection = (IList)parameter; ... }