VirtualizingStackPanel + MVVM +多选

dec*_*jau 26 wpf listview mvvm stackpanel virtualizingstackpanel

我已经实现类似于在所描述的一个的选择图案此篇使用视图模型来存储IsSelected值,并通过结合所述ListViewItem.IsSelected的视图模型IsSelected:

<ListView.ItemContainerStyle>
    <Style TargetType="{x:Type ListViewItem}">
        <Setter Property="IsSelected" Value="{Binding Mode=TwoWay, Path=IsSelected}"/>
    </Style>
</ListView.ItemContainerStyle>
Run Code Online (Sandbox Code Playgroud)

它一般工作,但我遇到了严重的问题.通过VirtualizingStackPanel在列表视图中使用a 作为面板,仅ListViewItem创建了可见的.如果我使用"Ctrl + A"选择所有项目,或者使用第一项上的"Shift + Ctrl + End"快捷键组合,则会选择所有项目,但对于不可见项目,ViewModel不会获取其IsSelected设为true.这是合乎逻辑的,因为如果ListViewItem没有创建,绑定就无法工作.

任何人都遇到了同样的问题,并找到了解决方案(除了不使用a VirtualizingStackPanel)?

dec*_*jau 33

我找到了另一种处理MVVM模式选择的方法,它解决了我的问题.不是在viewmodel中维护选择,而是从ListView/ListBox中检索选择,并将其作为参数传递给Command.全部在XAML中完成:

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

<Button 
    Content="Remove Selected" 
    Command="{Binding RemoveSelectedItemsCommand}" 
    CommandParameter="{Binding ElementName=_items, Path=SelectedItems}"/>
Run Code Online (Sandbox Code Playgroud)

在我的ViewModel中:

private void RemoveSelection(object parameter)
{
    IList selection = (IList)parameter;
    ...
}
Run Code Online (Sandbox Code Playgroud)

  • 我喜欢这种方法,但你不能以这种方式从viewmodel以编程方式选择项目. (5认同)
  • 如果 Listview 和按钮在不同的用户控制范围内,它也将不起作用。 (2认同)

Ped*_*iro 5

就我而言,我最终通过从ListBox派生一个ListBoxEx类并添加代码以响应选择更改来解决此问题,从而在项目视图模型上强制选择状态:

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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)