扩展选择模式,虚拟化和IsSelected绑定 [英] Extended selection mode, virtualization and IsSelected binding

查看:110
本文介绍了扩展选择模式,虚拟化和IsSelected绑定的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在扩展选择模式下,IsSelected绑定似乎有问题.看起来只有选择中的最后一项变得超出范围会被正确处理.

It seems in extended selection mode IsSelected binding is buggy. Looks like only last item from selection which become out of scope is handled properly.

演示:

项目012989796是通过 Control 选择的.选择94(不带 Control !)时,选择计数器应为1,但您看到的是3.向上滚动将显示未选择范围中只有(最后)一个选择项是什么.

Items 0, 1, 2 and 98, 97, 96 are selected with Control. When selecting 94 (without Control!) selection counter should be 1, but you see 3 instead. Scrolling up reveals what only one (last) item of selection out of scope was unselected.

以下是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)虚拟化:

A quick fix is to disable list control (ListBox or ListView) virtualization:

VirtualizingStackPanel.IsVirtualizing="False"

问题:您知道如何在不禁用虚拟化的情况下进行修复吗?

Question: any idea how to fix it without disabling virtualization?

推荐答案

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

Well, this is expected behavior. Virtualization only creates visual containers (ListBoxItem) for visible items. In order for bindings to work, the container must exist in the first place, so only visible items are affected.

有两种明显的解决方案:

There are two obvious solutions:

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

  1. Disable virtualization.
  2. Use SelectionChanged event instead. You can get added and removed items from SelectionChangedEventArgs. Then all you need to do is perform a cast and set the IsSelected property accordingly (you don't need to iterate over Items). Ctrl+A will work as well, you just have to handle added items too (and remove the binding altogether):

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();
}

这篇关于扩展选择模式,虚拟化和IsSelected绑定的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆