.net - WPF:绑定(bind)到 ListBoxItem.IsSelected 不适用于屏幕外项目

标签 .net wpf mvvm binding listbox

在我的程序中,我有一组 View 模型对象来表示 ListBox 中的项目(允许多选)。 viewmodel 有一个 IsSelected 属性,我想将其绑定(bind)到 ListBox,以便在 viewmodel 中而不是在列表框本身中管理选择状态。

但是,显然 ListBox 不维护大多数屏幕外项目的绑定(bind),因此通常 IsSelected 属性未正确同步。这是一些演示问题的代码。第一个 XAML:

<StackPanel>
    <StackPanel Orientation="Horizontal">
        <TextBlock>Number of selected items: </TextBlock>
        <TextBlock Text="{Binding NumItemsSelected}"/>
    </StackPanel>
    <ListBox ItemsSource="{Binding Items}" Height="200" SelectionMode="Extended">
        <ListBox.ItemContainerStyle>
            <Style TargetType="{x:Type ListBoxItem}">
                <Setter Property="IsSelected" Value="{Binding IsSelected}"/>
            </Style>
        </ListBox.ItemContainerStyle>
    </ListBox>
    <Button Name="TestSelectAll" Click="TestSelectAll_Click">Select all</Button>
</StackPanel>

C# 全选处理程序:
private void TestSelectAll_Click(object sender, RoutedEventArgs e)
{
    foreach (var item in _dataContext.Items)
        item.IsSelected = true;
}

C# View 模型:
public class TestItem : NPCHelper
{
    TestDataContext _c;
    string _text;
    public TestItem(TestDataContext c, string text) { _c = c; _text = text; }

    public override string ToString() { return _text; }

    bool _isSelected;
    public bool IsSelected
    {
        get { return _isSelected; }
        set {
            _isSelected = value; 
            FirePropertyChanged("IsSelected");
            _c.FirePropertyChanged("NumItemsSelected");
        }
    }
}
public class TestDataContext : NPCHelper
{
    public TestDataContext()
    {
        for (int i = 0; i < 200; i++)
            _items.Add(new TestItem(this, i.ToString()));
    }
    ObservableCollection<TestItem> _items = new ObservableCollection<TestItem>();
    public ObservableCollection<TestItem> Items { get { return _items; } }

    public int NumItemsSelected { get { return _items.Where(it => it.IsSelected).Count(); } }
}
public class NPCHelper : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    public void FirePropertyChanged(string prop)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(prop));
    }
}

可以观察到两个不同的问题。
  • 如果单击第一个项目,然后按 Shift+End,则应选择所有 200 个项目;但是,标题报告只选择了 21 个项目。
  • 如果单击“全选”,则确实选择了所有项目。如果您然后单击 ListBox 中的一个项目,您会希望取消选择其他 199 个项目,但这不会发生。相反,只有屏幕上的项目(以及其他一些项目)被取消选择。除非您首先从头到尾滚动列表,否则所有 199 个项目都不会被取消选择(即使这样,奇怪的是,如果您使用小滚动框执行滚动,它也不起作用)。

  • 我的问题是:
  • 有人可以准确解释为什么会发生这种情况吗?
  • 我可以避免或解决这个问题吗?
  • 最佳答案

    ListBox默认情况下,UI 是虚拟化的。这意味着在任何给定时刻,ItemsSource 中只有可见项目(以及“几乎可见”项目的一小部分子集)。实际会被渲染。这就解释了为什么更新源可以按预期工作(因为这些项目总是存在的),但只是导航 UI 不能(因为这些项目的视觉表示是动态创建和销毁的,并且永远不会同时存在。)

    如果您想关闭此行为,一个选项是设置 ScrollViewer.CanContentScroll=False在您的 ListBox 上.这将启用“平滑”滚动,并隐式关闭虚拟化。要显式禁用虚拟化,您可以设置 VirtualizingStackPanel.IsVirtualizing=False .

    关于.net - WPF:绑定(bind)到 ListBoxItem.IsSelected 不适用于屏幕外项目,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7097999/

    相关文章:

    c# - 在应用程序文件中找不到名为 "...Entities"的连接字符串,但它存在吗?

    c# - C# 中的字符串复数化和本地化

    c# - 将枚举绑定(bind)到 DataGrid ComboBox View

    wpf - WPF中的字符串引用绑定(bind)

    WPF DataGrid 单击以创建新项目

    .net - BehaviorSubject.First() 已过时,替代方法是什么?

    .net - OnPaint() 内部的 Graphics.Clear() 偶尔会导致通用 GDI+ 错误

    c# - Caliburn.Micro WindowManager找不到 View

    c# - 如何在辅助角色中使用 WCF 进行批量插入

    c# - 什么时候应该使用 HashSet<T> 类型?