VirtualizingStackPanel + MVVM + множественный выбор

Я реализовал шаблон выбора, аналогичный описанному в этом сообщении, используя ViewModel для сохранить значение IsSelected и привязав ListViewItem.IsSelected к ViewModel IsSelected:

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

В целом это работает, но я столкнулся с серьезной проблемой. Используя a VirtualizingStackPanel в качестве панели в списке, создаются только видимые ListViewItem. Если я использую «Ctrl + A» для выбора всех элементов или комбинацию клавиш, например «Shift + Ctrl + End» для первого элемента, все элементы выбираются, но для невидимых элементов ViewModel не получает свой IsSelected установлено значение true. Это логично, потому что, если ListViewItem не созданы, привязка работать не будет.

Кто-нибудь испытал ту же проблему и нашел решение (кроме отказа от использования VirtualizingStackPanel)?


person decasteljau    schedule 13.08.2009    source источник
comment
Попробуйте это полное решение этой проблемы: stackoverflow.com/a/29545790   -  person nvkokorin    schedule 09.04.2015


Ответы (3)


Я нашел другой способ обработки выбора в шаблоне MVVM, который решил мою проблему. Вместо сохранения выбора в модели просмотра выбор извлекается из ListView / ListBox и передается в качестве параметра команде. Все сделано в XAML:

<ListView 
    x:Name="_items"
    ItemsSource="{Binding Items}" ... />

<Button 
    Content="Remove Selected" 
    Command="{Binding RemoveSelectedItemsCommand}" 
    CommandParameter="{Binding ElementName=_items, Path=SelectedItems}"/>

в моей ViewModel:

private void RemoveSelection(object parameter)
{
    IList selection = (IList)parameter;
    ...
}
person decasteljau    schedule 13.08.2009
comment
Мне нравится этот подход, но вы не можете программно выбирать элементы из модели просмотра таким образом. - person M. Dudley; 13.01.2011
comment
Это также не будет работать, если Listview и кнопка находятся в разных областях пользовательского управления. - person Rakshit Bakshi; 16.09.2014

В моем случае я решил эту проблему, создав класс ListBoxEx из ListBox и добавив код для ответа на изменения выбора, обеспечивающий состояние выбора в моделях представления элементов:

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;
        }
    }
}
person Pedro Pombeiro    schedule 12.11.2009
comment
Идеально. Решает основную проблему, синхронизируя модель просмотра! - person RandomEngy; 25.03.2019

Помимо того, что я не использую VirtualizingStackPanel, единственное, что я могу придумать, - это захватить эти сочетания клавиш и иметь методы для изменения определенного диапазона ваших ViewModel элементов, чтобы их свойство IsSelected было установлено на True (например, SelectAll(), SelectFromCurrentToEnd()). В основном в обход Binding на ListViewItem для управления выбором в таких случаях.

person Joel B Fant    schedule 13.08.2009
comment
Не забывайте, что это может происходить разными способами с помощью клавиатуры или мыши! Ctrl + A, Shift + End, Shift + Home, и вы можете, удерживая Shift, щелкнуть мышью произвольный диапазон; все это может вызвать одну и ту же проблему. - person Qwertie; 11.11.2011