扩展选择模式,虚拟化和IsSelected绑定

时间:2016-05-31 09:31:03

标签: c# wpf mvvm selection virtualization

似乎在扩展选择模式IsSelected绑定是错误的。看起来只有选择中的最后一项超出范围才能正确处理。

演示:

使用 Control 选择项012989796 。选择94(不使用 Control !)时,选择计数器应为1,但您会看到3。向上滚动显示只有一个(最后一个)选择超出范围的项目未被选中。

以下是mcve:

XAML:

<ListBox ItemsSource="{Binding Items}" SelectionMode="Extended" SelectionChanged="ListBox_SelectionChanged">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Text}" />
        </DataTemplate>
    </ListBox.ItemTemplate>
    <ListBox.ItemContainerStyle>
        <Style TargetType="ListBoxItem">
            <Setter Property="IsSelected" Value="{Binding IsSelected}" />
        </Style>
    </ListBox.ItemContainerStyle>
</ListBox>

CS:

public class NotifyPropertyChanged : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    public void OnPropertyChanged([CallerMemberName] string property = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
}

public class Item : NotifyPropertyChanged
{
    bool _isSelected;
    public bool IsSelected
    {
        get { return _isSelected; }
        set { _isSelected = value; }
    }

    public string Text { get; set; }
}

public class ViewModel : NotifyPropertyChanged
{
    public ObservableCollection<Item> Items { get; }

    public ViewModel()
    {
        var list = new List<Item>();
        for (int i = 0; i < 100; i++)
            list.Add(new Item() { Text = i.ToString() });
        Items = new ObservableCollection<Item>(list);
    }
}

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = new ViewModel();
    }

    void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        Title = ((ViewModel)DataContext).Items.Count(item => item.IsSelected).ToString();
    }
}

快速解决方法是禁用列表控制(ListBoxListView)虚拟化:

VirtualizingStackPanel.IsVirtualizing="False"

问题:如何在不禁用虚拟化的情况下解决问题?

1 个答案:

答案 0 :(得分:3)

嗯,这是预期的行为。虚拟化仅为可见项创建可视容器(ListBoxItem)。为了使绑定起作用,容器必须首先存在,因此只有可见项受到影响。

有两个明显的解决方案:

  1. 禁用虚拟化。
  2. 请改用SelectionChanged事件。您可以从SelectionChangedEventArgs添加和删除项目。然后,您需要做的就是执行强制转换并相应地设置IsSelected属性(您不需要迭代Items)。 Ctrl + A也可以,你只需要处理添加的项目(并完全删除绑定):

    void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        foreach (var removedItem in e.RemovedItems.Cast<Item>())
        {
            removedItem.IsSelected = false;
        }
        foreach (var addedItem in e.AddedItems.Cast<Item>())
        {
            addedItem.IsSelected = true;
        }
        Title = ((ViewModel) DataContext).Items.Count(item => item.IsSelected).ToString();
    }