首页 > 解决方案 > 系统特定的 ListView 列宽更改行为

问题描述

背景:今天早些时候,我在 github 上发布了一个用 C# .NET 和 WinForms 编写的开源应用程序。最初下载它的几个人发现它在启动时立即崩溃。假设我以某种方式搞砸了分发,我在这里发布了一个问题。一些乐于助人的人下载了该项目并很快确定问题是由堆栈溢出引起的。

所以这已经解决了,但问题仍然存在:为什么我运行这段代码时不会崩溃?

特定问题是由每当窗口或另一列的大小发生更改时尝试调整详细信息模式 ListView 的最右边列的代码引起的。事件处理程序正在设置列的ColumnWidthChanged宽度,导致无限递归。

在我的系统上,它工作得很好(这里是视频)。一种可能的解释是我有一个特殊版本的 WinForms(或底层控件),如果列宽没有改变,它不会发布事件更改通知。

我真正想要的是高度确信在我的系统上运行的代码将在其他地方运行。回答我问题的人似乎很容易在他们的开发系统上重现崩溃。我是否设法安装了某种“防弹版”?

应用程序和库项目面向 .NET Framework 4.6.1 或 .NET Standard 2.0。将应用程序更改为目标 4.7.1 无效。我在 Windows 10 Pro 系统上使用 Visual Studio Community 2017,更新至 15.8.3。这是我第一次尝试桌面 C# .NET 应用程序,所以我可能在做一些愚蠢的事情。

更新:受到@jwdonahue 评论的启发,我进行了一个实验:在事件处理程序中,抓取 aStackTrace并检查FrameCount,记录看到的最大值。启用其中一个列更新后,我始终看到最大帧数为 414,并且ColumnWidthChanged存在多个事件处理程序实例。如果我注释掉列更新,最大计数下降到 174,我只看到一个事件实例。

@LexLi 转发的失败运行的堆栈跟踪有 5087 个条目,所以这不是我的堆栈限制更高的简单问题。

标签: c#.netwinforms

解决方案


可能是在您的系统上,它最终会将列宽设置为现有值。如果新值与当前值相同,则可能不会触发更改的事件。

可能的原因有:

  • 由于 DPI 不同,启动窗口大小可能会有所不同。
  • 数据可能不同,导致不同系统上的宽度不同。
  • 在失败的系统上,宽度可能不会收敛,而是在两个值之间交替。
  • 从理论上讲,它可能取决于 .net 框架或操作系统的版本。

无论哪种方式,从实际的角度来看,最好将您的软件设计为没有循环计算。


推荐阅读