Управление несколькими выборами с MVVM

На пути к изучению MVVM я приобрел некоторое базовое понимание WPF и шаблона ViewModel. Я использую следующую абстракцию при предоставлении списка и меня интересует один выбранный элемент.

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

Затем я могу связать OrdersView вместе с поддержкой сортировки и фильтрации в списке в WPF:

<ListView ItemsSource="{Binding Path=OrdersView}" 
          IsSynchronizedWithCurrentItem="True">

Это работает очень хорошо для одного выбора. Но я хотел бы также поддерживать несколько вариантов выбора в представлении и привязать модель к списку выбранных элементов.

Как бы я связал ListView.SelectedItems со свойством backer на ViewModel?

4 ответа

Решение

Добавить IsSelected собственность для вашего ребенка ViewModel (OrderViewModel в твоем случае):

public bool IsSelected { get; set; }

Привязать выбранное свойство в контейнере к этому (для ListBox в этом случае):

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

IsSelected обновляется в соответствии с соответствующим полем на контейнере.

Вы можете получить выбранные дочерние элементы в модели представления, выполнив следующие действия:

public IEnumerable<OrderViewModel> SelectedOrders
{
    get { return Orders.Where(o => o.IsSelected); }
}

Я могу заверить вас: SelectedItems действительно связывается как XAML CommandParameter

Существует простое решение этой общей проблемы; чтобы это работало, вы должны следовать ВСЕМ следующим правилам:

  1. Следуя совету Эда Болла, в привязке данных вашей команды XAML определите CommandParameter атрибут ДО Command приписывать. Это очень трудоемкая ошибка.

  2. Убедитесь, что ваш ICommand"s CanExecute а также Execute методы имеют параметр типа object, Таким образом, вы можете предотвратить исключения приведения с молчанием, возникающие всякий раз, когда привязка данных CommandParameter тип не соответствует вашему Command Тип параметра метода:

    private bool OnDeleteSelectedItemsCanExecute(object SelectedItems)  
    {
         // Your code goes here
    }
    
    private bool OnDeleteSelectedItemsExecute(object SelectedItems)  
    {
        // Your code goes here
    }
    

Например, вы можете отправить ListView/ListBox"s SelectedItems собственность на ваш ICommand методы или ListView/ListBox сам. Отлично, не правда ли?

Я надеюсь, что это мешает кому-то тратить огромное количество времени, которое я потратил, чтобы выяснить, как получить SelectedItems как CanExecute параметр.

Можно попытаться создать прикрепленное свойство.

Это спасет от добавления IsSelected свойство для каждого списка, который вы связываете. Я сделал это для ListBox, но он может быть изменен для использования в виде списка.

<ListBox SelectionMode="Multiple"
         local:ListBoxMultipleSelection.SelectedItems="{Binding SelectedItems}" >

Дополнительная информация: WPF - Binding ListBox SelectedItems - Присоединенное свойство VS Style.

Если вы используете MVVM-LIGHT, вы можете использовать этот шаблон:

https://galasoft.ch/posts/2010/05/handling-datagrid-selecteditems-in-an-mvvm-friendly-manner

Не особенно элегантно, но выглядит так, как минимум, должно быть надежно

Другие вопросы по тегам