避免使用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异常。
- RefreshItems()=>基于模型更新ListView
- ListView已更改,因此ItemChecked被调用的次数与我们拥有的项的次数一样多
- ItemChecked基于ListView更新模型
- 模型的改变导致cicle重新启动。转到1
在ItemChanged事件处理程序中,我无法检测是谁发起了更改(即,用户通过单击或RefreshItems方法通过填充项),因此我无法选择跳出无限循环。
我该如何解决这个问题?
在调用RefreshItems()之前,我将尝试分离ItemChanged的事件处理程序
然后重新连接。
listView.ItemChanged -= new ItemChangedEventHandler(myItemChangedEvent);
RefreshItems();
listView.ItemChanged += new ItemChangedEventHandler(myItemChangedEvent);
几个即时想法:
1) 如果itemChecked
状态在您的模型中设置了"不同"状态,则仅调用RefreshItems()
。在您的模型设置器中进行测试即可轻松完成。
2) 在RefreshItems()
中使用一些标志来注意您正在更新GUI的事实。如果设置了此标志,则不要在itemChecked
处理程序中执行任何操作。然而,这让我觉得既粗鲁又恶心。