如何最好地/高效地过滤 Treeview
节点?
例如:我输入了"abc",只有包含"abc"文本的节点会显示。然后我输入了"abcd",应该只看到包含"abcd"文本的节点。每次更改过滤条件时,TreeView
内容也会相应改变。
有什么想法吗?
如何最好地/高效地过滤 Treeview
节点?
例如:我输入了"abc",只有包含"abc"文本的节点会显示。然后我输入了"abcd",应该只看到包含"abcd"文本的节点。每次更改过滤条件时,TreeView
内容也会相应改变。
有什么想法吗?
如果你想要最佳的性能,先克隆树形结构,然后从克隆的树形结构中删除所有项目,接着将现有的树形结构简单替换为克隆的(和筛选过的)树形结构。
我还保留了一个始终未筛选的备份树形结构。
对于具有1000-2000个节点的相当大的树形结构,这对我非常有效。
public partial class winTree : TreeView
{
private NodesCollection allNodes = new NodesCollection();
[ReadOnly(true)]
public new NodesCollection Nodes { get { return allNodes; } }
private string filtro = string.Empty;
public String Filtro
{
get { return filtro; }
set { filtro = value; filtrarNodos(); }
}
public winTree()
{
InitializeComponent();
allNodes.NodeAdd += OnNodeAdd;
allNodes.NodeRemove += OnNodeRemove;
allNodes.NodesClear += OnNodesClear;
}
private void OnNodeAdd(object sender, EventArgs e)
{
TreeNode n = (TreeNode)sender;
if (passFilter(n))
{
base.Nodes.Add(n);
}
}
private void OnNodeRemove(object sender, EventArgs e)
{
base.Nodes.Remove((TreeNode)sender);
}
private void OnNodesClear(object sender, EventArgs e)
{
base.Nodes.Clear();
}
private void filtrarNodos()
{
this.BeginUpdate();
base.Nodes.Clear();
foreach(TreeNode n in this.Nodes)
{
if (passFilter(n))
{
base.Nodes.Add(n);
}
}
this.EndUpdate();
}
private bool passFilter(TreeNode nodo)
{
if (string.IsNullOrWhiteSpace(filtro))
{
return true;
}
else
{
return nodo.Text.ToLower().Contains(filtro.ToLower());
}
}
}
public class NodesCollection : IList<TreeNode>
{
private List<TreeNode> nodos = new List<TreeNode>();
public event EventHandler NodeAdd;
public event EventHandler NodeRemove;
public event EventHandler NodesClear;
private void OnNodeAdd(TreeNode nodo)
{
if (NodeAdd != null)
{
NodeAdd(nodo, EventArgs.Empty);
}
}
private void OnNodeRemove(TreeNode nodo)
{
if (NodeRemove != null)
{
NodeRemove(nodo, EventArgs.Empty);
}
}
private void OnNodesClear()
{
if (NodeRemove != null)
{
NodesClear(this, EventArgs.Empty);
}
}
#region IList<TreeNode>
public int IndexOf(TreeNode item)
{
return nodos.IndexOf(item);
OnNodeAdd(item);
}
public void Insert(int index, TreeNode item)
{
nodos.Insert(index, item);
OnNodeAdd(item);
}
public void RemoveAt(int index)
{
TreeNode nodo = nodos[index];
nodos.RemoveAt(index);
OnNodeRemove(nodo);
}
public TreeNode this[int index]
{
get
{
return nodos[index];
}
set
{
OnNodeRemove(nodos[index]);
nodos[index] = value;
OnNodeAdd(nodos[index]);
}
}
public void Add(TreeNode item)
{
nodos.Add(item);
OnNodeAdd(item);
}
public void Clear()
{
nodos.Clear();
OnNodesClear();
}
public bool Contains(TreeNode item)
{
return nodos.Contains(item);
}
public void CopyTo(TreeNode[] array, int arrayIndex)
{
nodos.CopyTo(array, arrayIndex);
}
public int Count
{
get { return nodos.Count(); }
}
public bool IsReadOnly
{
get { return true; }
}
public bool Remove(TreeNode item)
{
bool res = nodos.Remove(item);
if (res)
{
OnNodeRemove(item);
}
return res;
}
public IEnumerator<TreeNode> GetEnumerator()
{
return nodos.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return nodos.GetEnumerator();
}
#endregion
}
我想提供一个更好的解决方案,关键是我不想从一个新类中派生,减少涉及的代码。
我的解决方案:
按照正常方式构建树,不要进行过滤
备份树(下面的代码)(仅在进行搜索时才备份,而不是为了备份)
可以随意更改树,删除节点等
如果需要将树重置为初始状态,请调用_backup.Restore()
using System.Linq;
using System.Windows.Forms;
public class TreeViewBackup : List<TreeViewBackup>
{
public TreeNode Parent { get; }
public TreeNodeCollection Children { get; }
public TreeViewBackup(TreeNodeCollection children, TreeNode parent = null)
{
Parent = parent;
Children = children;
AddRange(Children.Cast<TreeNode>().Select(child => new TreeViewBackup(child.Nodes, child)));
}
public void Restore()
{
Children.Clear();
this.ForEach(clone => clone.Restore());
Children.AddRange(this.Select(n => n.Parent).ToArray());
}
}
public class Form1
{
public void Filter()
{
_backup = new TreeViewBackup(_treeView.Nodes);
_treeView.BeginUpdate();
MessWithMe();
_treeView.EndUpdate();
}
public void Undo()
{
_treeView.BeginUpdate();
_backup.Restore();
_treeView.EndUpdate();
}
}
TreeNodeCollection
吗?通过其子节点递归克隆每个TreeNode
?不是整个TreeView
控件,对吧? - Code Jockey