11

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

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

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

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

4

7 回答 7

21

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

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

于 2008-09-23T13:53:11.433 回答
15

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

  • 开始更新()
  • 加载 20.000 个节点
  • 结束更新()

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

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

于 2008-09-23T15:04:25.100 回答
7

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

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

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

于 2008-09-23T14:08:37.277 回答
7

注意:此答案因提问者的编辑而无效,他说他已经做过这种事情,但我决定仍然发布它以供其他人在此主题上搜索以供将来参考

当我过去做过类似的事情时,我倾向于选择天真的延迟加载风格。

  • 使用该TreeNode.Tag属性来保存可用于查找子项的引用
  • 使用TreeView.BeforeExpand事件填充子节点
  • 可以选择使用TreeView.AfterCollapse事件来删除它们。
  • 为了让 [+]/[-] 框出现,我发现的最好方法是创建一个单例虚拟对象TreeNode,将其作为子节点添加到所有未填充的节点,然后在填充之前检查它是否存在BeforeExpand
于 2008-09-23T14:27:59.367 回答
5

有一种方法可以使 TreeView 性能更好,那就是创建所有子节点并将它们连接在一起,然后将节点添加到 TreeView。如果是我们正在谈论的图形性能。

TreeView tree = new TreeView();
TreeNode root = new TreeNode("Root");
PopulateRootNode(root); // Get all your data
tree.Nodes.Add(root);

否则,使用OnTreeNodeExpanded 逐个节点加载它们。

于 2008-09-23T14:18:26.490 回答
1

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

这种模式也适用于数据检索。如果您真正从数千或数百万条记录的源中加载数据,您可能不想预先加载所有这些。没有用户愿意等待加载,也没有理由加载可能永远不会查看的数据。

我通常会根据需要在后台线程上加载孙子或曾孙节点数据,然后将这些数据编组回 UI 线程并创建和添加节点。这使 UI 具有响应性。您可以在视觉上装饰树节点以指示它们仍在加载,以应对用户领先于您的 IO 到数据存储的情况。

于 2008-09-23T14:49:47.397 回答
0

这对我有用(CSharp):

    Visible = false;
    ...
    Visible = true;

在我的情况下(2000 个节点),加载树只需要 1~2 秒,这比任何其他方式都快得多。它可能在 C++ 中运行良好。

于 2022-02-23T13:51:02.800 回答