我尝试扩展winforms TreeView控件以允许增量过滤和搜索,类似于VS2012 / VS2013中的解决方案资源管理器。
理想情况下,我希望它能够用最少的代码更改替换现有的TreeView - 就消费者而言,唯一的区别是方法void Filter(string)
。因此,我认为Nodes
属性返回带有所有节点的TreeNodeCollection
是有意义的,即使是因为应用了过滤器而未显示的节点。
我编写的代码用于处理过滤,它实际上运行良好,除非我访问base.Nodes
时,它返回我的过滤节点而不是完整列表。
我遇到的问题是,我无法克隆或创建TreeNodeCollection
的新实例,因为构造函数被标记为内部。所以我的理想代码看起来像这样:
public class TreeViewEx : TreeView
{
// results in a compiler error:
private TreeNodeCollection _allNodes = new TreeNodeCollection();
public new TreeNodeCollection Nodes { get { return _allNodes; } }
public TreeNodeCollection FilteredNodes { get { return base.Nodes; } }
public void Filter(string searchString)
{
base.BeginUpdate();
base.Nodes.Clear();
foreach (TreeNode node in FilterInternal(_allNodes, searchString))
{
base.Nodes.Add(node);
}
base.EndUpdate();
}
}
正如您所看到的,我试图将UI中显示的节点与消费者可以访问的节点分离。当然TreeNodeCollection
只有一个内部构造函数,我无法创建新实例或克隆它。
我考虑了这两个选项,但听起来都不是很好的解决方案:
TreeNodeCollection
对象(由于内部构造函数)。这个选项似乎比#2更有效,但我当然要创建一个我不应该做的对象实例。我希望最终结果仍然是TreeNodeCollection
,因此可以使用TreeView以最少的代码替换我们现有的控件,并且我们使用Find
方法确实有几个地方,而不是{39} ; t存在于List<TreeNode>
。
有没有人对如何处理这个有任何建议?我的两个考虑因素在性能/资源方面呢?
谢谢
更新1:
根据Pat的建议,我决定退一步,避免完全弄乱Nodes
。所以现在我添加了List<TreeNode> AllNodes
属性并让Nodes
只显示TreeView中出现的节点(已过滤的列表),所以现在它更简单了。
我现在的问题是,我如何知道AllNodes
何时添加了一个项目,以便我可以让Nodes
保持同步?我考虑使用BindingList
,因此我有ListChanged
事件,但后来我需要拥有我的TreeNode和节点的子/幼子/等({{1使用继承自AllNodes[0].Nodes
的自定义类并更改TreeNode
属性,Nodes
不可覆盖。还有另外一种方法吗?我可以创建一个名为NodeExs的新属性,但这看起来非常不直观,我可以看到另一个开发人员随后出现并拔出他的头发因为Nodes属性存在但不起作用。
答案 0 :(得分:1)
关于您提出的解决方案,#2已经出局,因为TreeNode
不能属于多个控件。虽然可以通过反射创建TreeNodeCollection
的实例,但它不会非常有用,因为它被设计为耦合到TreeView
或另一个TreeNode
。您无法从集合中添加/删除节点。
因此,我认为Nodes属性才有意义 返回TreeNodeCollection与所有节点,甚至是未显示的节点 因为应用过滤器。
我不同意,框架和操作系统使用TreeNodeCollection
属性返回的Nodes
来呈现控件。你真的不想隐藏这个属性或改变它的功能。
如果消费者需要访问_allNodes
,请创建List<TreeNode> AllNodes
属性或使用自定义集合。
答案 1 :(得分:1)
我发现TreeNodeCollection
只应用于读取列出的节点。相反,我使用List<TreeNode>
列出节点。在我的项目中,我为List<TreeNode>
上的每个级别创建了TreeView
。当我在启动时填充TreeView
时,我同时填写了列表。最后,我使用AddRange()
来制作和组合所有节点的列表。这样我就列出并分类了所有节点。
创建此类列表非常简单快捷。我还创建了所有节点列表的List<string>
版本,我为AutoCompleteCustomSource
设置为TextBox
。通过这种方式,我可以使用TextBox
和AutoComplete
来搜索节点。
我会为消费者和其他类别制作不同的列表。然后我只会将项目添加到符合给定条件的TreeView
。您还可以使用treeView.Nodes.Remove()
删除任何节点。您仍然将实际节点存储在列表中,并可以稍后再将其添加回来。
这些只是一些想法。