我有一个 WPF 窗口,其中包含一个 ListBox 控件,当执行按钮单击方法时会填充该控件。
XAML:
<ListBox Name="ThirdPartyListBox" ItemsSource="{Binding}" Margin="0,70,0,0">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Source="C:\Users\Test\Desktop\Project\ACME-WPF\ACME-WPF\window-new-3.ico" Margin="5" Width="50"/>
<Button Name="ThirdPartyInstallButton" Content="Install" Click="InstallThirdPartyUpdatesButton_Click" Margin="5,5,0,0" Height="25"></Button>
<Button Name="ThirdPartyPostoneButton" Content="Postpone" Click ="PostponeThirdPartyUpdatesButton_Click" Margin="5,5,0,0" Height="25"></Button>
<TextBlock FontWeight="Bold" Text="{Binding Item2.Name}" Margin="12,25,0,0"/>
<TextBlock FontWeight="Bold" Text="{Binding Item2.RequiredVersion}" Margin="3,25,0,0"/>
<TextBlock Text="{Binding Item2.CustomUIMessage}" Margin="10,25,0,0" TextWrapping="Wrap" Foreground="Red"/>
<TextBlock Text="You have used " Margin="3,25,0,0"/>
<TextBlock Text="{Binding Item3.UsedDeferrals}" Margin="3,25,0,0"/>
<TextBlock Text=" of " Margin="3,25,0,0"/>
<TextBlock Text="{Binding Item2.MaxDefferals}" Margin="3,25,0,0"/>
<TextBlock Text=" deferrals for this update." Margin="3,25,0,0"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
C#:
private void CheckforThirdPartyUpdatesButton_Click(object sender, RoutedEventArgs e)
{
CheckforThirdPartyUpdatesButton.IsEnabled = false;
worker = new BackgroundWorker();
worker.WorkerReportsProgress = true;
worker.WorkerSupportsCancellation = true;
worker.DoWork += delegate(object s, DoWorkEventArgs args)
{
MainEntry.checkFor3PUpdates();
};
worker.ProgressChanged += delegate(object s, ProgressChangedEventArgs args)
{
};
worker.RunWorkerCompleted += delegate(object s, RunWorkerCompletedEventArgs args)
{
ThirdPartyListBox.DataContext = RegScan_ThirdParty.comparisonListWithState;
CheckforThirdPartyUpdatesButton.IsEnabled = true;
};
worker.RunWorkerAsync();
}
到目前为止,一切都按预期运行,并且列表框中填充了多行项目,具体取决于列表中有多少项目
ThirdPartyListBox.DataContext = RegScan_ThirdParty.comparisonListWithState;
。但是,如果我与列表框项进行交互,则会引发 InvalidOperationException 并带有内部异常“ItemsControl 与其项源不一致。”
有人可以帮助我了解发生了什么事吗?
当项目的源已从另一个线程更改并且
ListBox
未收到有关 CollectionChanged
更改的通知(ItemsSource
事件)时,会引发此类异常;所以当它开始做一些工作(比如更新布局)时,它会发现 Items
不等于 ItemsSource
并抛出异常。
自 .NET 4.5 起,WPF 提供了一种方法来启用与不同线程更改的集合的同步。尝试在您的 EnableCollectionSynchronization
上使用
ItemsSource
方法。请参阅类似问题的答案中的示例用法
您可以在更改绑定资源的控件上简单地调用 Refresh() 方法:
myListBox.Items.Refresh();
我也有同样的错误。这是由于编辑列表中用作 ItemsSource 的对象引起的。
我的解决方案是用 ObservableCollection 替换 List。 根据 .NET 文档,ObservableCollection:
“表示动态数据集合,当添加、删除项目或刷新整个列表时提供通知。”
我遇到了完全相同的错误消息,因为我在一个方法中多次(循环)清除并更新具有 UI 绑定的列表。
解决方案是创建一个临时列表并仅分配新列表一次。
不是直接你的问题,而是同样的错误,所以我想我会在这里提到它......
我遇到了同样的错误“ItemsControl 与其项目源不一致”,但我是从 UI 线程执行所有操作的。我正在使用一个实现
ICollectionView
作为 ItemsSource
的类。我自己开发了这个视图。
问题在于,在引发
ICollectionView.GetEnumerator()
事件之前,视图并未使从 CollectionChanged
返回的枚举器无效。 ItemsSource
在内部缓存枚举器以及使用它们获得的任何结果。如果枚举器没有失效,它会很乐意重用它们和派生值,包括项目计数。
要使枚举器无效,请从其
InvalidOperationException
属性以及 Current
和 MoveNext()
方法中抛出 Reset()
。然后,ItemsControl
将请求一个新的枚举器并重新创建缓存的数据。如果您的枚举器实现了 IDisposable
,它也会首先调用 Dispose()
。
如果您的集合实现了 INotifyCollectionChanged,您还可以发送 NotifyCollectionChangedAction.Reset 消息,基本上是说“我把一切都搞砸了,让我们重新开始吧。”