C#中的慢树视图

我有一个用C#编写的遗留应用程序,它显示了一个非常复杂的树视图,包含10到2万个元素。

在过去,我遇到了类似的问题(但在C ++中),我用Win32 API提供的OWNERDATAfunction解决了这个问题。

C#中是否有类似的机制?

编辑:计划是优化创建时间和浏览时间。 通过Win32 API提供的方法在这两种情况下都非常出色,因为它将初始化时间减少到无,并且元素的请求数量仅限于任何时候可见的数量。 Joshl:我们实际上正在做你已经提出的建议,但我们仍然需要更高的效率。

我不相信.NET TreeView支持你想要的东西,尽管.NET的DataGridView支持这种类型的模型(参见DataGridView的VirtualMode属性)。 TreeView将允许您绘制自己的节点,但它不允许您从某个虚拟商店填充它们。

如果可能,您可能需要考虑为您的应用程序使用DataGridView。 如果没有,手动管理节点(如上面提到的joshl)可能会有效,如果您可以解决在扩展节点时正确刷新屏幕的一些问题。 除此之外 ,你可能想看看一些第三方供应商,比如这个(Divelements SandGrid) ,可能(强调可能)支持你想要的操作模式。

注意:截至2013年7月底,Divelements不支持SandGrid。

一种提高性能的技术是在用户扩展树视图时加载TreeNodes。 通常,用户不需要一次在其屏幕上打开20,000个节点。 仅加载用户需要查看的级别,以及正确显示用户可用性所需的任何子信息(如果存在子项,计数,图标等,则展开图标)。 当用户扩展节点时,及时加载子节点。

来自Keith的有用提示:使用winforms TreeView,您需要至少有一个子节点,否则它将不会显示展开[+],但是您将处理TreeNodeExpanded事件以删除该虚拟节点并填充子节点。

在我们的主WinForm应用程序中,我们一次性加载了一个树视图:

  • 的BeginUpdate()
  • 加载20.000个节点
  • EndUpdate()

到目前为止,性能仍然很好。 它实际上是我们没有用第三方替换的少数组件之一。

根据我的经验,当您加载节点(一次性或按需)而不调用Begin / EndUpdate()时,TreeView性能会变慢,特别是如果您的节点已排序,但如果您正确调用Begin / EndUpdate(),则不应该真正得到与组件本身相关的性能问题。

注意:这个答案被提问者的编辑声称他已经做过这样的事情而无效,但我决定将其发布以供将来参考此主题的其他人参考

当我过去做过类似的事情时,我倾向于选择天真的懒人装载风格。

  • 使用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逐节点加载它们。

对于Windows C#编程中的大数据,无论是在WPF还是WinForms中,我传统上都是动态添加节点。 我加载了初始树根+儿童+孙子深。 当任何节点被扩展时,我加载代表扩展节点的孙子的树节点(如果有的话)。

此模式也适用于数据检索。 如果您真正从数千或数百万条记录的来源加载数据,您可能不希望预先加载这些数据。 没有用户想要等待加载,并且没有理由加载可能永远不会被查看的数据。

我通常在后台线程上根据需要加载孙子或孙子节点数据,然后将这些数据封送回UI线程并创建和添加节点。 这使得UI响应。 您可以在视觉上装饰树节点,以指示它们仍在加载用于用户超出IO数据存储的情况。