Gestión de selecciones múltiples con MVVM
-
03-07-2019 - |
Pregunta
En mi viaje hacia el aprendizaje de MVVM, he establecido cierta comprensión básica de WPF y el patrón de ViewModel. Estoy utilizando la siguiente abstracción al proporcionar una lista y estoy interesado en un solo elemento seleccionado.
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 ); }
}
Luego puedo enlazar el OrdersView junto con la clasificación y el filtro compatibles a una lista en WPF:
<ListView ItemsSource="{Binding Path=OrdersView}"
IsSynchronizedWithCurrentItem="True">
Esto funciona realmente bien para vistas de selección individuales. Pero también me gustaría admitir selecciones múltiples en la vista y hacer que el modelo se vincule a la lista de elementos seleccionados.
¿Cómo enlazaría ListView.SelectedItems a una propiedad de respaldo en ViewModel?
Solución
Agregue una propiedad IsSelected
a su hijo ViewModel ( OrderViewModel
en su caso):
public bool IsSelected { get; set; }
Enlazar la propiedad seleccionada en el contenedor a esto (para ListBox en este caso):
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="IsSelected" Value="{Binding Mode=TwoWay, Path=IsSelected}"/>
</Style>
</ListBox.ItemContainerStyle>
IsSelected
se actualiza para que coincida con el campo correspondiente en el contenedor.
Puede obtener los elementos secundarios seleccionados en el modelo de vista haciendo lo siguiente:
public IEnumerable<OrderViewModel> SelectedOrders
{
get { return Orders.Where(o => o.IsSelected); }
}
Otros consejos
Le puedo asegurar: SelectedItems
es de hecho vinculable como un CommandParameter
XAML
Hay una solución simple para este problema común; para que funcione, debe seguir TODOS las siguientes reglas:
-
Siguiendo la sugerencia de Ed Ball , en el enlace de datos del comando XAML, defina el
CommandParameter
atributo ANTES del atributoComando
. Este es un error que consume mucho tiempo . -
Asegúrese de que los métodos de
ICommand
deCanExecute
yExecute
tengan un parámetro de tipoobjeto
. De esta manera, puede evitar que las excepciones de conversión silenciadas se produzcan cuando el tipo de parámetroCommandParameter
del enlace de datos no coincida con el tipo de parámetro del métodoCommand
:private bool OnDeleteSelectedItemsCanExecute(object SelectedItems) { // Your code goes here } private bool OnDeleteSelectedItemsExecute(object SelectedItems) { // Your code goes here }
Por ejemplo, puede enviar la propiedad ListView
/ ListBox
de SelectedItems
a sus métodos de ICommand
o el ListView
/ ListBox
en sí mismo. Genial, ¿no?
Espero que esto evite que alguien pase la gran cantidad de tiempo que hice para averiguar cómo recibir SelectedItems
como un parámetro CanExecute
.
Uno puede intentar crear una propiedad adjunta.
Al hacerlo, se guardará uno al agregar la propiedad IsSelected
para cada una de las listas que enlaza. Lo he hecho para ListBox
, pero se puede modificar para usarlo en una vista de lista.
<ListBox SelectionMode="Multiple"
local:ListBoxMultipleSelection.SelectedItems="{Binding SelectedItems}" >
Más información: WPF - Binding ListBox SelectedItems - Property Attached VS Style .
Si está utilizando MVVM-LIGHT, puede usar este patrón:
No es especialmente elegante, pero parece que debería ser confiable al menos