我有一个包含这些数据的假设树视图:
RootNode
Leaf
vein
SecondRoot
seeds
flowers
我正在尝试过滤节点,以便仅显示包含特定文本的节点。假如我指定“L”,树将被过滤并仅显示RootNode-> Leaf和SecondRoot->花(因为它们都包含字母L)。
遵循m-v-vm模式,我有一个基本的TreeViewViewModel类,如下所示:
public class ToolboxViewModel
{
...
readonly ObservableCollection<TreeViewItemViewModel> _treeViewItems = new ObservableCollection<TreeViewItemViewModel>();
public ObservableCollection<TreeViewItemViewModel> Headers
{
get { return _treeViewItems; }
}
private string _filterText;
public string FilterText
{
get { return _filterText; }
set
{
if (value == _filterText)
return;
_filterText = value;
ICollectionView view = CollectionViewSource.GetDefaultView(Headers);
view.Filter = obj => ((TreeViewItemViewModel)obj).ShowNode(_filterText);
}
}
...
}
一个基本的TreeViewItemViewModel:
public class ToolboxItemViewModel
{
...
public string Name { get; private set; }
public ObservableCollection<TreeViewItemViewModel> Children { get; private set; }
public bool ShowNode(string filterText)
{
... return true if filterText is contained in Name or has children that contain filterText ...
}
...
}
所有内容都在xaml中设置,所以我看到了树视图和搜索框。
执行此代码时,过滤器仅适用于不足的根节点。有没有办法让过滤器在节点层次结构中流淌,以便为每个节点调用我的谓词?换句话说,过滤器可以作为一个整体应用于TreeView吗?
答案 0 :(得分:7)
这是我过滤TreeView
上的项目的方式:
我有课:
class Node
{
public string Name { get; set; }
public List<Node> Children { get; set; }
// this is the magic method!
public Node Search(Func<Node, bool> predicate)
{
// if node is a leaf
if(this.Children == null || this.Children.Count == 0)
{
if (predicate(this))
return this;
else
return null;
}
else // Otherwise if node is not a leaf
{
var results = Children
.Select(i => i.Search(predicate))
.Where(i => i != null).ToList();
if (results.Any()){
var result = (Node)MemberwiseClone();
result.Items = results;
return result;
}
return null;
}
}
}
然后我可以将结果过滤为:
// initialize Node root
// pretend root has some children and those children have more children
// then filter the results as:
var newRootNode = root.Search(x=>x.Name == "Foo");
答案 1 :(得分:4)
不幸的是,没有办法让相同的Filter自动应用于所有节点。 Filter是ItemsCollection的一个属性(不是DP),它不是DependencyObject,因此DP Value继承不存在。
树中的每个节点都有自己的ItemsCollection,它有自己的Filter。使其工作的唯一方法是手动将它们全部设置为调用相同的委托。
最简单的方法是公开Predicate&lt; object&gt;类型的Filter属性在你的ToolBoxViewModel和它的setter中触发一个事件。然后ToolboxItemViewModel将负责使用此事件并更新其Filter。
很漂亮,我不确定树中大量项目的表现会是什么样的。
答案 2 :(得分:3)
我发现这样做的唯一方法(这有点像黑客攻击)是创建一个从IList转换为IEnumerable的ValueConverter。在ConvertTo()中,从传入的IList返回一个新的CollectionViewSource。
如果有更好的方法,我很乐意听到它。但这似乎有用。
答案 3 :(得分:2)
我决定使用Philipp Sumi提到的树视图:http://www.codeproject.com/KB/WPF/versatile_treeview.aspx
并对其应用过滤器,如下所示:http://www.hardcodet.net/2008/02/programmatically-filtering-the-wpf-treeview
我不能推荐它:)
答案 4 :(得分:1)
为什么需要过滤器或CollectionSource?这是处理TreeView项的简单MVVM方法。
您只需使用DataTriggers即可使项目可见,折叠,更改颜色,突出显示,闪烁等等。
.hero-image-row {
margin-top: -50px !important;
overflow-x: hidden !important;
width: 100% !important;
vertical-align: top;
}
我将把完整的示例包含在我的WPF库中:
https://www.codeproject.com/Articles/264955/WPF-MichaelAgroskin
答案 5 :(得分:0)
您可以使用ItemContainerGenerator
获取树中给定元素的TreeViewItem,一旦有了,您就可以设置过滤器。