VirtualizingStackPanel + MVVM + selección múltiple
-
16-09-2019 - |
Pregunta
He implementado un patrón de selección similar a la descrita en este post el uso de un ViewModel para almacenar la IsSelected valor, y mediante la unión de la ListViewItem.IsSelected
a la Perspective IsSelected:
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="IsSelected" Value="{Binding Mode=TwoWay, Path=IsSelected}"/>
</Style>
</ListView.ItemContainerStyle>
Funciona en general, pero me encuentro con un grave problema.Mediante el uso de la un VirtualizingStackPanel
como el panel en la vista de lista, sólo visible ListViewItem
está siendo creado.Si puedo usar "Ctrl+a" para seleccionar todos los elementos, o mediante la combinación de teclas tales "Mayús+Ctrl+Fin" en el primer ítem, todos los artículos seleccionados, pero para los que no los elementos visibles, el ViewModel no obtener su IsSelected establece en true.Es lógico, porque si la ListViewItem
no se crean, la unión no puede trabajar.
Nadie experimentado el mismo problema y encontrar una solución (aparte de no usar un VirtualizingStackPanel
)?
Solución
He encontrado otra manera 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 la ListView / ListBox, y pasa como 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 modelo de vista:
private void RemoveSelection(object parameter)
{
IList selection = (IList)parameter;
...
}
Otros consejos
En mi caso, terminé la solución de este derivando una clase ListBoxEx de ListBox, y la adición de código para responder a los cambios de selección, hacer cumplir el estado de selección de los modelos de vista del elemento:
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;
}
}
}
Además de no usar VirtualizingStackPanel
, lo único que puedo pensar es capturar esos atajos de teclado y tienen métodos para modificar una determinada gama de sus artículos ViewModel
modo que su propiedad IsSelected
se establece en True
(por ejemplo, SelectAll()
, SelectFromCurrentToEnd()
) . Básicamente sin pasar por el Binding
en ListViewItem
para el control de la selección para estos casos.