// 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");
Unfortunately there is no way to make same Filter apply to all nodes automatically. Filter is a property (not a DP) of ItemsCollection which is not DependencyObject and so DP Value inheritance isn't there.
Each node in the tree has its own ItemsCollection which has its own Filter. The only way to make it work is to manually set them all to call the same delegate.
Simplest way would be to expose Filter property of type Predicate<object> at your ToolBoxViewModel and in its setter fire an event. Then ToolboxItemViewModel will be responsible for consuming this event and updating its Filter.
Aint pretty and I'm not sure what the performance would be like for large amounts of items in the tree.
–
The only way I've found to do this (which is a bit of a hack), is to create a ValueConverter that converts from IList to IEnumerable. in ConvertTo(), return a new CollectionViewSource from the passed in IList.
If there's a better way to do it, I'd love to hear it. This seems to work, though.
Why do you need filters or CollectionSource? Here is a simple MVVM way to handle TreeView items.
You can make items visible, collapsed, change color, highlight, flash, whatever, simply by using DataTriggers:
public class Item : INotifyPropertyChanged
public string Title { get; set; } // TODO: Notify on change
public bool VisibleSelf { get; set; } // TODO: Notify on change
public bool VisibleChildOrSelf { get; set; } // TODO: Notify on change
public ObservableCollection<Item> Items { get; set; } // TODO: Notify on change
public void CheckVisibility(string searchText)
VisibleSelf = // Title contains SearchText. You may use RegEx with wildcards
VisibleChildOrSelf = VisibleSelf;
foreach (var child in Items)
child.CheckVisibility(searchText);
VisibleChildOrSelf |= child.VisibleChildOrSelf;
public class ViewModel : INotifyPropertyChanged
public ObservableCollection<Item> Source { get; set; } // TODO: Notify on change
public string SearchText { get; set; } // TODO: Notify on change
private void OnSearchTextChanged() // TODO: Action should be delayed by 500 millisec
foreach (var item in Source) item.CheckVisibility(SearchText);
<StackPanel>
<TextBox Text="{Binding SearchText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
MinWidth="200" Margin="5"/>
<TreeView ItemsSource="{Binding Source}" Margin="5">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Items}">
<TextBlock Text="{Binding Title}" />
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
<TreeView.ItemContainerStyle>
<Style TargetType="Control">
<Style.Triggers>
<DataTrigger Binding="{Binding VisibleChildOrSelf}" Value="false">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
<DataTrigger Binding="{Binding VisibleSelf}" Value="false">
<Setter Property="Foreground" Value="Gray"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
<StackPanel>
I'm going to include the complete example into my WPF library:
https://www.codeproject.com/Articles/264955/WPF-MichaelAgroskin
–
I decided to use the treeview by Philipp Sumi mentioned here : http://www.codeproject.com/KB/WPF/versatile_treeview.aspx
And applied a filter to it as shown here : http://www.hardcodet.net/2008/02/programmatically-filtering-the-wpf-treeview
I couldn't recommend it enough :)
–
You can set the same filter for all TreeViewItems of the hierarchy with this extension method:
public static class TreeViewExtensions {
/// <summary>
/// Applies a search filter to all items of a TreeView recursively
/// </summary>
public static void Filter(this TreeView self, Predicate<object> predicate)
ICollectionView view = CollectionViewSource.GetDefaultView(self.ItemsSource);
if (view == null)
return;
view.Filter = predicate;
foreach (var obj in self.Items) {
var item = self.ItemContainerGenerator.ContainerFromItem(obj) as TreeViewItem;
FilterRecursively(self, item, predicate);
private static void FilterRecursively(TreeView tree, TreeViewItem item, Predicate<object> predicate)
ICollectionView view = CollectionViewSource.GetDefaultView(item.ItemsSource);
if (view == null)
return;
view.Filter = predicate;
foreach (var obj in item.Items) {
var childItem = tree.ItemContainerGenerator.ContainerFromItem(obj) as TreeViewItem;
FilterRecursively(tree, childItem, predicate);
With above extension method it becomes as easy as myTreeView.Filter(myPredicate);
to apply the predicate to the entire hierarchy.
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.