2009-08-13 9 views
22

He implementado un patrón de selección similar al descrito en this post usando un modelo de vista para almacenar el valor IsSelected, y mediante la unión del ListViewItem.IsSelected a la ViewModel IsSelected:VirtualizingStackPanel + MVVM + selección múltiple

<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 el a 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 el ListViewItem no se crea, el enlace no puede funcionar.

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

+0

Pruebe esta solución completa para este problema: http://stackoverflow.com/a/29545790 – nvkokorin

Respuesta

28

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 modelo de vista:

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

Me gusta este enfoque, pero no puede seleccionar elementos programáticamente desde el modelo de vista de esta manera. –

+1

Tampoco funcionará si Listview y el botón están en un ámbito de control de usuario diferente. –

1

Aparte 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 ViewModel elementos para que su propiedad IsSelected se establece en True (por ejemplo, SelectAll(), SelectFromCurrentToEnd()) Básicamente omitiendo el Binding en ListViewItem para controlar la selección de dichos casos.

+2

¡No olvide las diferentes formas en que esto puede suceder con el teclado o el mouse! Ctrl + A, Shift + End, Shift + Inicio, y puede hacer Shift-clic en un rango arbitrario con el mouse; todas estas cosas pueden causar el mismo problema. – Qwertie

3

En mi caso, terminé la solución de este derivando una clase ListBoxEx del cuadro de lista, y la adición de código para responder a los cambios de selección, haciendo cumplir el estado de selección de los modelos de vista material:

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