我有一个用C#编写的遗留应用程序,它显示了一个非常复杂的树视图,包含10到2万个元素.
在过去,我遇到了类似的问题(但在C++中),我用Win32 API提供的OWNERDATA功能解决了这个问题.
C#中是否有类似的机制?
编辑:计划是优化创建时间和浏览时间.通过Win32 API提供的方法在这两种情况下都非常出色,因为它将初始化时间减少到无,并且元素请求的数量仅限于任何时候可见的数量.Joshl:我们实际上已经完成了你的建议,但我们仍然需要更高的效率.
一种提高性能的技术是在用户扩展树视图时加载TreeNodes.通常,用户不需要一次在屏幕上打开20,000个节点.仅加载用户需要查看的级别,以及正确显示用户可用性所需的任何子信息(如果存在子项,计数,图标等,则展开图标).当用户扩展节点时,及时加载子节点.
来自Keith的有用提示:使用winforms TreeView,您需要至少有一个子节点,否则它不会显示展开[+],但是您将处理TreeNodeExpanded事件以删除该虚拟节点并填充子节点.
在我们的主要WinForm应用程序中,我们一次性加载了一个树视图:
的BeginUpdate()
加载20.000个节点
EndUpdate()
到目前为止,性能仍然很好.它实际上是我们没有用第三方替换的少数组件之一.
根据我的经验,当您加载节点(一次性或按需)而不调用Begin/EndUpdate()时,TreeView性能会变慢,特别是如果您的节点已排序,但是如果正确调用Begin/EndUpdate(),则不应该真正得到与组件本身相关的性能问题.
我不相信.NET TreeView支持你想要的东西,尽管.NET的DataGridView支持这种类型的模型(参见DataGridView的VirtualMode属性).TreeView将允许您绘制自己的节点,但它不允许您从某个虚拟商店填充它们.
如果可能,您可能需要考虑为您的应用程序使用DataGridView.如果没有,手动管理节点(如上面提到的joshl)可能会有效,如果您可以解决在扩展节点时正确刷新屏幕的一些问题.除此之外,你可能想要查看一些第三方供应商,比如这个(Divelements SandGrid),可能(强调可能)支持你想要的操作模式.
注意:截至2013年7月底,Divelements不支持SandGrid.
注意:这个答案通过提问者编辑说他已经做过这种事情而无效,但我决定将其发布以供将来参考此主题的其他人参考
当我过去做过类似的事情时,我倾向于选择天真的懒人装载风格.
使用该TreeNode.Tag
属性可以保存可用于查找子项的引用
使用该TreeView.BeforeExpand
事件填充子节点
(可选)使用该TreeView.AfterCollapse
事件删除它们.
为了显示[+]/[ - ]框,我发现的最好方法是创建一个单独的虚拟对象TreeNode
,作为子节点添加到所有未填充的节点,并在填充之前检查它是否存在BeforeExpand
.
有一种方法可以使TreeView执行得更好,即创建所有子节点并将它们连接在一起,然后将节点添加到TreeView.如果这是我们正在讨论的图形性能.
TreeView tree = new TreeView(); TreeNode root = new TreeNode("Root"); PopulateRootNode(root); // Get all your data tree.Nodes.Add(root);
否则,使用OnTreeNodeExpanded逐节点加载它们.