C# &引用;ItemsControl与其items源“不一致”;调用MessageBox.Show()时引发
我对WPF非常陌生,我有以下问题: 我正试图开发一个实践应用程序来帮助我控制我的预算 我有一个这样的班级聚会:C# &引用;ItemsControl与其items源“不一致”;调用MessageBox.Show()时引发,c#,wpf,C#,Wpf,我对WPF非常陌生,我有以下问题: 我正试图开发一个实践应用程序来帮助我控制我的预算 我有一个这样的班级聚会: public class Partida { public delegate void PartidaChangedHandler(Partida p); public event PartidaChangedHandler OnPartidaChanged; private ObservableCollection<PartidaEntry> co
public class Partida
{
public delegate void PartidaChangedHandler(Partida p);
public event PartidaChangedHandler OnPartidaChanged;
private ObservableCollection<PartidaEntry> content;
public Partida()
{
content = new ObservableCollection<PartidaEntry>();
content.CollectionChanged += PartidaEntriesCollectionChanged;
}
public void PartidaEntriesCollectionChanged(object s, NotifyCollectionChangedEventArgs args)
{
if (OnPartidaChanged != null)
{
OnPartidaChanged(this);
}
}
}
当我在DataGrid中添加新行时,事件会正确触发,但是一旦执行MessageBox,我就会收到一条带有以下消息的invalidoOperationException
:
ItemsControl与其items源不一致
你知道如何在不失去监听ObservaleCollection的CollectionChanged事件并在该事件发生后触发PartIdChanged的能力的情况下修复该问题吗
提前谢谢
另外,我想知道MessageBox和ItemControl到底有什么关系。。。如果MessageBox只显示一个简单的框,为什么会触发异常!:S中的答案清楚地解释了发生的情况:在更改集合的操作正在进行时调用事件处理程序,调用MessageBox.Show()
使dispatcher消息处理循环有机会再次开始处理消息。这会导致与WPF工作方式不兼容的重入:集合更改操作尚未完全解决,但UI有机会尝试运行在该操作完全解决之前不应运行的逻辑
换句话说,就像异常状态一样,控件处于不一致的状态,因为它被允许进行一些处理,而这些处理在完全处理集合更改之后才应该发生
我承认,另一个答案中的建议并不十分令人信服。就目前而言,这是一个合理的建议,但没有提供真正的替代方案
在您的场景中,在不改变任何其他实现的情况下,一个明显的解决方案是将消息框延迟到集合更改操作完全解决之后。您可以通过使用Dispatcher.InvokeAsync()
方法来延迟对MessageBox.Show()的调用执行:
当然,有一个问题是,显示消息框是否真的是处理事件的最佳方式。从您问题中有限的信息来看,我们并不清楚事件处理程序为何看起来如此。如果您确信在每次集合更改时显示消息框确实是正确的做法,那么上述操作应该可以解决您的问题
但您可能需要考虑将信息呈现给用户的其他方法,例如在UI中的状态字段中显示它,甚至提供一些事件日志,例如在多行文本框或列表框中。这类方法通常会涉及符合WPF中事件和数据处理正常流程的数据绑定,并且可以作为同步代码工作,而不会遇到您在这里看到的问题。
您可以发布ItemsControl的xaml吗?我在这里发现了另一个与此问题完全相同的问题()。选择的答案只是删除MessageBox.Show(),事实上他们说删除整个CollectionChanged事件处理程序。然而,这并不能真正解决问题@我的链接答案怎么解决不了你的问题?删除MessageBox.Show()调用后是否仍会发生异常?你能澄清一下吗?
p.OnPartidaChanged += (Partida ppp) =>
{
int foo = 5;
MessageBox.Show("A partida has changed!");
};
p.OnPartidaChanged += (Partida ppp) =>
{
int foo = 5;
Dispatcher.InvokeAsync(() => MessageBox.Show("A partida has changed!"));
};