Подтвердить что ты не робот

VirtualizationStackPanel + 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)?

4b9b3361

Ответ 1

Я нашел другой способ обработки выбора в шаблоне 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;
    ...
}

Ответ 2

В моем случае я решил это решить, выведя класс 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;
        }
    }
}

Ответ 3

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