VirtualizingStackPanel + MVVM + множественный выбор
Я реализовал шаблон выбора, аналогичный описанному в этом посте, используя ViewModel для хранения значения IsSelected и связывая ListViewItem.IsSelected
выбранной ViewModel:
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="IsSelected" Value="{Binding Mode=TwoWay, Path=IsSelected}"/>
</Style>
</ListView.ItemContainerStyle>
В целом это работает, но я сталкиваюсь с серьезной проблемой. Используя VirtualizingStackPanel
в качестве панели в виде списка, только видимые ListViewItem
создаются Если я использую "Ctrl+A" для выбора всех элементов или с помощью сочетания клавиш, такого как "Shift+Ctrl+End", для первого элемента, все элементы выбираются, но для невидимых элементов ViewModel не получает свой IsSelected установите в true. Это логично, потому что если ListViewItem
не создаются, привязка не может работать.
Кто-нибудь сталкивался с такой же проблемой и нашел решение (кроме того, что не использовал VirtualizingStackPanel
)?
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;
...
}
В моем случае я решил эту проблему, извлекая класс 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;
}
}
}
Помимо неиспользования VirtualizingStackPanel
единственное, о чем я могу думать, это захватить эти сочетания клавиш и иметь методы для изменения определенного диапазона ваших ViewModel
предметы, так что их IsSelected
свойство установлено в True
(например, SelectAll()
, SelectFromCurrentToEnd()
). В основном в обход Binding
на ListViewItem
для контроля выбора для таких случаев.