使用 ItemsSource 时操作无效。改为使用 ItemsControl.ItemsSource 访问和修改元素

Posted

技术标签:

【中文标题】使用 ItemsSource 时操作无效。改为使用 ItemsControl.ItemsSource 访问和修改元素【英文标题】:Operation is not valid while ItemsSource is in use. Access and modify elements with ItemsControl.ItemsSource instead 【发布时间】:2012-06-20 19:00:38 【问题描述】:

我是 Binding 和 WPF 的新手,最近我学会了如何使用 Binding 技术创建具有多列的 listBox

 <ListView ItemsSource="Binding Items" Margin="306,70,22,17" MouseDoubleClick="listBoxSS_MouseDoubleClick" Name="listBoxSS" >           
    <ListView.View>
            <GridView>
                <GridView.Columns>
                    <GridViewColumn Header="first_name " Width="100" DisplayMemberBinding="Binding Path=First_name" />
                    <GridViewColumn Header="last_name" Width="100" DisplayMemberBinding="Binding Path=Last_name" />
                    <GridViewColumn Header="phone_number" Width="100" DisplayMemberBinding="Binding Path=Phones[0]" />
                    <GridViewColumn Header="notes" Width="100" DisplayMemberBinding="Binding Path=Notes" />
                </GridView.Columns>
            </GridView>
        </ListView.View>
    </ListView>

这是代码:

List<Student> arr = search.students();
        listBoxSS.ItemsSource = arr;

但问题是当我尝试使用添加或删除项目或清除时

 listBoxSS.Items.Clear();

我需要一个使用项目来源的示例,或者我可以添加或删除项目或清除列表的方式。

编辑:

<ListView ItemsSource="Binding Items" Margin="306,70,22,17" MouseDoubleClick="listBoxSS_MouseDoubleClick" Name="listBoxSS" >
    <ListView.View>
        <GridView>
            <GridView.Columns>
                <GridViewColumn Header="first_name " Width="100" DisplayMemberBinding="Binding Path=First_name" />
                <GridViewColumn Header="last_name" Width="100" DisplayMemberBinding="Binding Path=Last_name" />
                <GridViewColumn Header="phone_number" Width="100" DisplayMemberBinding="Binding Path=Phones[0]" />
                <GridViewColumn Header="notes" Width="100" DisplayMemberBinding="Binding Path=Notes" />
            </GridView.Columns>
        </GridView>
    </ListView.View>
</ListView>

这里是代码:

 ObservableCollection<Employee> Gemployees;
var employees = new ObservableCollection<Employee>(search.employees());

search.employees() 获取我数据库中所有员工的列表

 listBoxPE.ItemsSource = employees;
        Gemployees = employees;

现在我可以在 Gemployees 上执行所有方法

 Gemployees.Remove((Student)listBoxSS.SelectedItem);
 Gemployees.Add((Student)listBoxSS.SelectedItem);

ListView 在我从 Gemployees 中添加或删除项目时执行刷新!很酷,但在装订方面还是有点辛苦。现在我正在为每个 ListView 做一个接口类,这样我就可以把我的东西放进去。它不会在添加项目中执行任何灵活性。

【问题讨论】:

【参考方案1】:

您将ItemsSource 绑定到DataContext 中名为Items 的属性,因此要更新集合,您需要转到DataContext 中的Items 属性并清除它。

此外,Items 属性必须是 ObservableCollection 类型,而不是 List,如果您希望它在底层集合更改时更新 UI。

不需要您在后面的代码中设置ItemsSource 的代码,应该将其删除。您只需将ItemsSource 设置在一处,无需同时设置。

这里有一个简单的例子来说明它是如何工作的:

// Using Students instead of Items for the PropertyName to clarify
public ObservableCollection<Student> Students  get; set; 

public MyConstructor()

    ...

    Students = search.students();
    listBoxSS.DataContext = this;

现在你有:

<ListView ItemsSource="Binding Students" ... />

你将ItemsSource绑定到ObservableCollection&lt;Student&gt;,当你想清除列表时,你可以调用:

Students.Clear()

【讨论】:

非常感谢,它现在可以进行一些更改,我将编辑我的问题,以便您可以看到我做了什么 我想在从列表中删除项目时更新 UI 元素。所谓的 TwoWay 绑定是不行的。 @PaulMcCarthy 您是否在使用 ObservableCollection,它会自动引发更改通知,让 UI 知道它需要更新?常规 List 不会这样做。 @Rachel,是的,但显然我错过了其他一些实际更新的东西 - 所以我抱怨它被称为“双向绑定”。这有点像声称汽车有电动车窗,但当你按下按钮时什么也没有发生。【参考方案2】:

奇怪但真实:我的 XAML 文件中的以下错误击键产生了错误“在使用 ItemsSource 时操作无效。改为使用 ItemsControl.ItemsSource 访问和修改元素。”:

</ItemsControl.ItemTemplate>x`

注意结束元素标记后的x` 字符。

【讨论】:

是的,奇怪但真实:我写了以下内容:>(注意双右括号) 谢谢。标签内的额外字符是这里的罪魁祸首。 哈!就我而言,我写的是“>”而不是“/>”,所以一个元素永远不会关闭。现在,为什么在构建时没有检测到这种事情? 这里发生的情况是 标记之间的任何“松散文本”都将被视为要添加到 ItemsCollection 的数据。我犯了与 Maxim 完全相同的双右括号错误——因为我告诉它使用 ItemsSource 绑定到数据源,并且还意外地将带有文本“>”的单个硬编码项放入。【参考方案3】:

我知道这个问题大约在 2 年前就已经得到了回答,但是我自己也遇到了这个问题,并且自己想出了一个可行的解决方案。也许这在某些情况下不起作用,也许我根本没有看到什么,但它对我有用,所以我在这里分享它:

listView.ClearValue(ItemsControl.ItemsSourceProperty);
listView.ItemsSource = NewSource;

我真诚地希望这对某人有所帮助。

【讨论】:

它对我有用,而且是一种更简单的方法。 这类似于从汽车上拆下发动机换档然后重新装上。但是,鉴于 WPF 的设计如此糟糕,我正在使用它来使其工作。如此简单的更新所替代的大量代码块是不值得的。【参考方案4】:

我认为the answer above 不太清楚。与流氓角色有关,这也会导致异常:

<ItemsControl ItemsSource="Binding AnObservableCollection">
    <Label Content="Binding Name"/>
</ItemsControl>

当你的意思是:

<ItemsControl ItemsSource="Binding AnObservableCollection">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <Label Content="Binding Name"/>
            </StackPanel>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

很容易认为第一个是正确的,异常并不能解释什么是错误的。

【讨论】:

我不确定这是否与流氓字符案例的根本原因相同。在这种情况下,您尝试以两种方式添加项目 - 1. 通过 ItemsSource 绑定,以及 2. 作为直接内容添加(标签)。两者都有效,但不能同时有效。 它引发了同样的异常,这是我第一次学习 wpf 时犯的一个错误。我认为这对搜索该异常的人会有所帮助。我真的不在乎根本原因是什么。 我同意你的例子很有帮助。 这是我的问题。谢谢一百万。【参考方案5】:

您需要处理数据绑定到您的ItemsSource 的集合。为了获得集合更改通知(添加或删除项目时),您应该使用ObservableCollection&lt;T&gt;

var students = new ObservableCollection<Student>(search.students());
listBoxSS.ItemsSource = students;

students.Clear();
students.Add(new Student("ABC"));

您应该从 XAML 中删除 ItemsSource="Binding Items" 声明。

【讨论】:

这不起作用,因为 ItemsSource 已设置,未绑定。因此对students 的更改不会反映在ListView @Rachel:实际上,不,对students 集合的更改更新ListView。数据绑定到属性的唯一区别是,当另一个 collection 分配给该属性时,它也可以引发通知(假设该类实现了INotifyPropertyChanged)。 你是对的,它实际上正在正确更新。这让我感到惊讶,因为我很确定我在设置值而不是绑定它时将属性设置为对象的副本,因此更新属性不会更新 UI。我仍然认为设置值而不是绑定它是不好的做法,但通常会建议不要这样做:) 如果您将 another 值分配给属性,那么是的,更改只会传播到属性数据绑定到的 UI。但是,如果您要更改分配给属性的实例 inin 的内容,那么一个简单的分配就足够了(假设实例内部实现了更改通知机制——例如,在这种情况下,@ 987654332@). 我想我在想一个CollectionViewSource,实际上你最终会绑定到SomeCollection.DefaultView(),而不是实际上SomeCollection :)【参考方案6】:

由于语法错误,我出现了相同的错误消息。事实证明,我不小心在 TreeView 中定义了一个已定义 ItemsSource 的项目。我为树视图定义了一个DataTemplate,但不小心把它直接放在&lt;TreeView&gt;而不是&lt;TreeView.Resources&gt;中,导致错误。

我有什么:

<TreeView ItemSource ="Binding Items">
  <HierarchicalDataTemplate> ... </HierarchicalDataTemplate>
  <DataTemplate> ... </DataTemplate>
</TreeView>

我应该拥有的:

<TreeView ItemSource ="Binding Items">
  <TreeView.Resources>
    <HierarchicalDataTemplate> ... </HierarchicalDataTemplate>
    <DataTemplate> ... </DataTemplate>
  </TreeView.Resources>
</TreeView>

【讨论】:

【参考方案7】:

将列表框的 ItemsSource 属性分配给表单类中的公共属性。然后尝试从中添加删除,在 setter 中调用 PropertyChanged,而不是直接在列表框项目源上调用 clear。

【讨论】:

你能给我举个例子吗?【参考方案8】:

始终将 ItemsSource 绑定到 ObservableCollection 以避免内存泄漏。 ObservableCollection 还将导致显示通过添加/删除自动更新。在我学会这一点之前,我曾经总是绑定到数组。

一个有用的来源: https://onewindowsdev.com/2016/09/22/a-memory-leak-may-occur-when-you-use-data-binding-in-windows-presentation-foundation/

1) 对于一般的 DataBinding,您绑定到的类应该实现 INotifyPropertyChanged。例外情况是使用 Mode=OneTime 绑定。

2) ItemsSource 应始终是实现 INotifyCollectionChange 的类。最简单的方法是使用 ObservableCollection。 ObservableCollection 确实有一个构造函数,它接受一个我发现有用的 IEnumerable。

3) 如果 ItemsControl 是 ObservableCollection,那么 SomeClass 应该实现 INotifyPropertyChange。然后,您可以安全地绑定到 SomeClass 的各个属性。

【讨论】:

请提供此链接的摘要,因为它可能有一天会失效 我已经添加了一些关于 DataBinding 的提示。【参考方案9】:

我遇到了同样的问题,我最终意识到我试图将新项目直接添加到控件的 ItemsSource,而不是添加到用作 ItemsSource 的 ObservableCollection。

我想我会发布这个,因为它可能会帮助其他新手 wpfer。

【讨论】:

【参考方案10】:

对我来说,这是完全不相关的问题。这是一个愚蠢的语法错误,我忘记用&lt;DataGrid.Style&gt; &lt;/DataGrid.Style&gt; 包装我的&lt;style&gt; &lt;/style&gt;

感谢 Microsoft 提供完全令人困惑的错误消息。

【讨论】:

【参考方案11】:

对我来说,问题是我误解了控件的说明,不小心把它放在了 datagrid 控件内部而不是外部。

    <DataGrid> 
        <mytag the tag for the open source control />
    </DataGrid>

上面有人提到了无关字符,我突然意识到 DataGrid 可能不喜欢那里。我移动了它,瞧,错误

使用 ItemsSource 时操作无效。改为使用 ItemsControl.ItemsSource 访问和修改元素。

不见了!它确实与 ItemsSource 没有任何关系,但无论解析器生成 Microsoft 错误,它都会让人感到困惑。

【讨论】:

以上是关于使用 ItemsSource 时操作无效。改为使用 ItemsControl.ItemsSource 访问和修改元素的主要内容,如果未能解决你的问题,请参考以下文章

WP8 LongListSelector - 重新分配 ItemsSource 无效

在DataGrid完成使用异步ItemsSource加载后执行某些操作?

更改 DataGrid.ItemsSource 时如何引发事件

当其 ItemsSource 更改时自动刷新 Datagrid

使用 MVVM 将新项目添加到 TabControl ItemSsource 时选择最后一个 TabItem

为啥更改 ItemsSource 时 DataGrid 不更新?