I have a treeview that has a hierarchical data. I'd like to add a filter to it so, I could search any element up to n-level. To do that, I find the concept of nested collectionviewsource
interesting. But I'm not sure how it will programmatically work.
Suppose we have a Collection of groups and each group has a collection of elements. So, how do I write a nested collectionviewsource
so, I could filter the search result of all the elements in all groups?
Here's a sample code that I thought it should work but it only filters the data on the first level and does not goes down to search 'Elements'. So, I wonder how do I write a right nested collectionviewsource
to filter the hierarchical data in a treeview.
<UserControl.Resources>
<CollectionViewSource x:Key="CollectionViewSourceGroups" x:Name="_CollectionViewSourceGroups" Source="{Binding Groups}" Filter="_filterGroups"/>
<CollectionViewSource x:Key="CollectionViewSourceElements" x:Name="_CollectionViewSourceElements" Source="{Binding Elements, Source={StaticResource CollectionViewSourceGroups}}" Filter="_filterElements"/>
</UserControl.Resources>
Here's the code that would trigger the filter command:
var cvs = TryFindResource("CollectionViewSourceGroups") as CollectionViewSource;
if (cvs != null)
{
if (cvs.View != null)
cvs.View.Refresh();
}
cvs = TryFindResource("CollectionViewSourceElements") as CollectionViewSource;
if (cvs != null)
{
if (cvs.View != null)
cvs.View.Refresh();
}
Edit: Here's the sample MVVM and XAML code:
/// <summary>
/// Group of Views
/// </summary>
public class ViewGroup : INotifyPropertyChanged
{
public string Name { get; set; }
public List<ViewGroup> Groups { get; set; }
private List<ProjectObject> _elements;
public List<ProjectObject> Elements
{
get { return _elements; }
set
{
_elements = value;
OnPropertyChanged();
}
}
public ViewGroup()
{
Groups = new List<ViewGroup>();
Elements = new List<ProjectObject>();
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class SheetManagerViewModel
{
public static SheetManagerViewModel Instance;
public ObservableCollection<ViewGroup> Groups { get; set; }
public SheetManagerViewModel()
{
Instance = this;
Groups = new ObservableCollection<ViewGroup>();
}
}
<Grid Grid.Row="1">
<Grid>
<TreeView x:Name="ProjectBrowserTreeView" ItemsSource="{Binding Groups}" MouseMove="ProjectBrowserTreeView_OnMouseMove" DragOver="ProjectBrowserTreeView_OnDragOver" >
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Groups}" DataType="{x:Type local:ViewGroup}">
<Label Content="{Binding Name}"/>
<HierarchicalDataTemplate.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Elements}" DataType="{x:Type local:ViewGroup}">
<Label Content="{Binding Name}"/>
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate DataType="{x:Type local:ProjectObject}">
<Label Content="{Binding Name}"/>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Grid>
</Grid>