为什么WinForms中的TreeView会意外折叠?

4
除了调用TreeNode的.Collapse()方法或TreeView的.CollapseAll()方法之外,还有什么原因会导致TreeView折叠?
在我开发的应用程序中,TreeView表现不正常。TreeView仅维护两个级别。选择父节点的子节点时,所有其他节点立即折叠。但是,我的代码中没有任何.Collapse()或.CollapseAll()方法调用!
TreeView的所有属性都保持默认值,除了.LabelEdit属性设置为true。TreeView具有一些代码与AfterLabelEdit事件相关联,用于简单的验证/MessageBox例程。
我尝试过:
- 钩住TreeView的BeforeCollapse事件并引发e.CancelAction标志。 - 在TreeView的AfterSelect事件中手动展开所有节点。(这作为实验很好,但我不打算完全禁止节点折叠!)
在代码的许多点上,我正在逐个节点地迭代TreeView以检查属性。但是,没有添加或删除节点。用户进行选择时修改的唯一TreeNode属性是.ImageIndex和.SelectedImageIndex。
除了上面提到的两种解决方案外,我没有任何线索可以说明此错误的原因。即使无法实现任何解决方案,是否有人知道捕获折叠的正确方法?(我已经尝试在BeforeCollapse事件中设置断点,但除非用户通过鼠标或键盘明确折叠节点,否则不会触发它。)
我发现问题是由于更改任何TreeNode的.SelectedImageIndex属性引起的。更改此属性会导致所有其他节点折叠。
我尝试使用.BeginUpdate()和.EndUpdate()调用包围.SelectedImageIndex属性修改代码,但没有效果。
如何避免这种情况发生?
1个回答

10
这是Windows本地窗口方式的一个副作用。许多窗口选项在CreateWindowEx()调用中通过样式标志指定,例如窗体边框的外观、ListView应该采用何种视图,TreeView是否应显示复选框等。这些样式以控件属性的形式呈现。但问题在于,更改此类属性需要从头重新创建窗口,以便在CreateWindowEx()调用中指定新的样式标志。这将带来一些副作用,窗口将完全重建,因此失去了所有先前的状态。
Windows Forms在使其看起来平滑方面做得相当不错,并在重建窗口后还原了先前的状态。但是仍会出现些许泄漏和一些明显的错误。例如,在TreeView中存在一个泄漏,即哪些节点折叠,哪些节点不折叠的确切状态。跟踪这一点并不实际。
通过将TreeView的Handle属性放入观察窗口进行诊断。如果看到它发生变化,则找到了该属性。样式标志列表可在此处查看,您可能可以将其名称映射到相应的属性。
也许很明显,除了避免更改该属性,没有更好的解决方法。这种麻烦也引发了WPF的诞生。

感谢您提供如此全面的答案!我已经能够确定导致树重新创建的属性,并避免在初始化后继续使用它。现在,这棵树不再忘记节点状态了。 - James
@HansPassant,能告诉我为什么您撤销了我的编辑吗?谢谢。 - Neuron

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接