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
)?
Ответы
Ответ 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
для управления выбором для таких случаев.