我没有测试或尝试过以下内容,但我想我还是会试一试。
首先,用 NSTableView 或 NSOutlineView 用 NS*Controller 管理任何复杂的东西是很痛苦的,并且为了简单而牺牲了精确的控制。如果您发现自己在这种情况下的行为举止,请考虑在您自己的自定义控制器中实现数据源和委托协议(NSTableViewDataSource、NSTableViewDelegate 或 NSOutlineViewDataSource、NSOutlineViewDelegate)。
其次,Warren Burton 关于触发 KVO 通知的评论是相关的,因为您应该告诉负责的控制器(您的 NSTreeController)有关更改,因为无论如何它是控制(和观察)该集合的人。更重要的是,您应该直接使用 NSTreeController 的 add/insert/remove 方法。您现在执行此操作的方式(每次将整个结构无效化,然后稍后将其重置)将导致整个树重新加载。由于控制器正在观察该集合,它告诉大纲视图刷新自己,可能允许它首先看到一个空的大纲,然后是大纲的进一步扩展版本,这将失去用户的扩展状态,等等。修改通过树控制器的模型将允许更智能,
第三,您可以考虑通过继承 NSTreeController 并覆盖 add/insert/remove 方法来利用我上面的第二点来执行以下操作:
- 询问其大纲视图
-visibleRect
。
- 调用 super 以启动更改。
- 告诉大纲视图
-scrollRectToVisible:
。
您可能必须通过在主线程上调度它来延迟第 3 步中的调用(因此它发生在当前通过运行循环的行程之后)。或者,或者,将步骤 3 替换为将可见矩形存储在某处并实现 NSOutlineViewDelegate-outlineView:didAdd/RemoveRowView:forRow:
方法来检查此标志-scrollRectToVisible:
,如果矩形非零,则从那里调用(记得将其重置为 NSZeroRect,这样它就不会尝试调整滚动每次添加或删除大纲行时)。
笨重,但合理的(?)路径允许您保留 NSTreeController。
第四,或者(以及我将采用的方式),您可以完全放弃 NSTreeController 并在您自己的控制器类中实现 NSOutlineViewDataSource(和 NSOutlineViewDelegate)协议,并让该控制器直接处理添加到树结构或从树结构中删除。然后它变得更干净,因为您不必担心 KVO 时间。在添加任何节点时,您可以注意可见的矩形,更新大纲视图,然后在同一方法中调整所有滚动并通过运行循环。
我希望这会有所帮助,并且不会太漫无边际。:-)