避免使用WinForm ListView进行循环调用(和StackOverflowException)

本文关键字:调用 循环 StackOverflowException WinForm ListView | 更新日期: 2023-09-27 18:29:05

我在保持我的模型(表示为List)与ListView同步方面遇到了问题(没有使用数据绑定)。

  • ListView的每一项都对应于列表中的MyObject实例
  • ListView还允许选中/取消选中与MyObject.IsVisible属性相对应的项

当前解决方案:每当MyObject列表发生更改时,我都有一个RefreshItems()方法,它会擦除ListView的内容并重新生成其项。我还实现了ListView的ItemChecked事件。每当用户选中/取消选中项目时,我都会修改相应的MyObject.IsVisible属性。

问题是在后端更改MyObject.IsVisible时。ListView中相应的复选框将不会更新。

失败的修复:不知怎的,我不得不将MyObject.IsVisible的状态更改级联到ListView。例如,通过调用RefreshItems()。每当执行RefreshItems()时,就会自动调用ListView.ItemChanged事件。这导致了一个无限循环和stackoverflow异常。

  1. RefreshItems()=>基于模型更新ListView
  2. ListView已更改,因此ItemChecked被调用的次数与我们拥有的项的次数一样多
  3. ItemChecked基于ListView更新模型
  4. 模型的改变导致cicle重新启动。转到1

在ItemChanged事件处理程序中,我无法检测是谁发起了更改(即,用户通过单击或RefreshItems方法通过填充项),因此我无法选择跳出无限循环。

我该如何解决这个问题?

避免使用WinForm ListView进行循环调用(和StackOverflowException)

在调用RefreshItems()之前,我将尝试分离ItemChanged的事件处理程序
然后重新连接。

listView.ItemChanged -= new ItemChangedEventHandler(myItemChangedEvent);
RefreshItems();
listView.ItemChanged += new ItemChangedEventHandler(myItemChangedEvent);

几个即时想法:

1) 如果itemChecked状态在您的模型中设置了"不同"状态,则仅调用RefreshItems()。在您的模型设置器中进行测试即可轻松完成。

2) 在RefreshItems()中使用一些标志来注意您正在更新GUI的事实。如果设置了此标志,则不要在itemChecked处理程序中执行任何操作。然而,这让我觉得既粗鲁又恶心。