WPF绑定IsSelected to ViewModel不会设置列表中未显示的项

WPF绑定IsSelected to ViewModel不会设置列表中未显示的项,wpf,data-binding,listview,binding,mvvm,Wpf,Data Binding,Listview,Binding,Mvvm,我有一个ViewModel,它有一个IsSelected属性,我在ListView.ItemContainerStyle XAML中将其绑定到视图模型中的IsSelected属性 我打开应用程序并填充视图模型集合,该集合在我的ListView中显示了许多项,比如说2000项。然后,我通过Ctrl-A选择列表中的所有内容。我的视图模型集合中的项目仅获取ListView中可见项目的IsSelected集。如果我向下翻阅列表,无论显示什么项目,都会设置IsSelected。如果我对所有项进行分页,则视

我有一个ViewModel,它有一个IsSelected属性,我在ListView.ItemContainerStyle XAML中将其绑定到视图模型中的IsSelected属性

我打开应用程序并填充视图模型集合,该集合在我的ListView中显示了许多项,比如说2000项。然后,我通过Ctrl-A选择列表中的所有内容。我的视图模型集合中的项目仅获取ListView中可见项目的IsSelected集。如果我向下翻阅列表,无论显示什么项目,都会设置IsSelected。如果我对所有项进行分页,则视图模型中的所有项都将IsSelected属性设置为true

以下是我的XAML,用于将列表视图中选择的IsSelected绑定到我的视图模型:

<ListView Margin="5" ItemsSource="{Binding FilteredComparisonList}" x:Name="comparisonListView">
    <ListView.ItemContainerStyle>
        <Style TargetType="{x:Type ListBoxItem}">
            <Setter Property="IsSelected" Value="{Binding Mode=TwoWay, Path=IsSelected}" />
        </Style>
    </ListView.ItemContainerStyle>
    <ListView.View>
        <GridView>
            <GridViewColumn Header="Source filename" DisplayMemberBinding="{Binding ImageFile.BaseFilename}" Width="Auto" />
        </GridView>
    </ListView.View>
</ListView>

为什么当我选择ListView中的所有项目时,我的视图模型中的所有项目的IsSelected没有设置为true?

这是因为ListView内置了虚拟化。如果你不熟悉这一点,它的基本意思是,这些物品在你看到之前是不会变成现实的。您可以使用以下属性关闭ListView的虚拟化:

VirtualizingStackPanel.IsVirtualizing="False"

但请注意,这将对ListView的性能产生不利影响。对于2000个项目来说,这不会很严重,但可能会很明显。

ListBoxItem是虚拟化的,只有当它们进入视图时生成,它们才存在。但是,基础ListView是从具有SelectedItems属性的ListBox派生的。SelectedItems是所有选定项目的列表,而不是选定的ListBoxItems列表。当ListBoxItem进入视图时,它的IsSelected属性将根据它所显示的项目是否在SelectedItems集合中而设置

这是视图模型的一个问题,尤其是如果您需要虚拟化,而您可能需要对2000个左右的项目进行虚拟化。我感兴趣的是这个问题的答案:如果某个项位于列表框的SelectedItems集合中,如何根据该项绑定视图模型IsSelected属性


答案可能涉及一个转换器

MVVM实现这一点的方法是使用您自己的SelectAll命令覆盖Ctrl-a快捷方式创建一个SelectAll命令,快捷方式为Ctrl-a。实现将在视图模型上设置IsSelected

视图中的IsSelected属性需要与视图模型具有双向绑定,以便项目在视图中显示为选中

我认为没有必要关闭虚拟化


希望这能有所帮助。

我也遇到了同样的问题,这就是最终帮助我的原因:

在列表视图中输入:


我将在另一个论坛上发布这个答案,因为它帮助我解决了这个问题

我已经定义了一个可供ViewModels实现的接口

public interface ISelectable
{
    bool IsSelected { get; set; }
}
然后在MyCustomListView中,我完成了以下操作:

public class MyCustomListView : ListView
{
    protected override void OnSelectionChanged(SelectionChangedEventArgs e)
    {
        foreach (var item in e.AddedItems.OfType<ISelectable>())
            item.IsSelected = true;

        foreach (var item in e.RemovedItems.OfType<ISelectable>())
            item.IsSelected = false;

        base.OnSelectionChanged(e);
    }
}

或者,您也可以订阅ListView的SelectionChanged事件,并使用上面相同的代码。

顺便说一句,这个问题本质上与这个问题相同:谢谢Charlie,我不知道我怎么错过了那篇文章。这篇文章有一个很好的解决方案,就是将所选项目作为CommandParameter传递进来,而不是在视图模型中维护IsSelected。
public class MyCustomListView : ListView
{
    protected override void OnSelectionChanged(SelectionChangedEventArgs e)
    {
        foreach (var item in e.AddedItems.OfType<ISelectable>())
            item.IsSelected = true;

        foreach (var item in e.RemovedItems.OfType<ISelectable>())
            item.IsSelected = false;

        base.OnSelectionChanged(e);
    }
}