i have a treeView which i loaded data with ItemsSource like this:
[ObservableProperty]
private ObservableCollection<FileSystemItem> items = new ObservableCollection<FileSystemItem>();
private async Task LoadFolder(string folderPath, ObservableCollection<FileSystemItem> parentCollection)
{
foreach (string directoryPath in Directory.EnumerateDirectories(folderPath))
{
var directoryInfo = new DirectoryInfo(directoryPath);
var directoryNode = new FileSystemItem(directoryInfo);
await LoadFolder(directoryPath, directoryNode.Children);
parentCollection.Add(directoryNode);
}
foreach (string filePath in Directory.EnumerateFiles(folderPath))
{
var fileInfo = new FileInfo(filePath);
var fileNode = new FileSystemItem(fileInfo);
parentCollection.Add(fileNode);
}
}
now, i want to search in my treeview, i am using following code:
Items = new(Search(query, _backupItems));
public IEnumerable<FileSystemItem> Search(string query, ObservableCollection<FileSystemItem> nodes)
{
foreach (var node in nodes)
{
if (node.DisplayName.Contains(query, StringComparison.OrdinalIgnoreCase))
{
yield return node;
}
foreach (var result in Search(query, node.Children))
{
yield return result;
}
}
}
but there is 2 issues: 1.after searching and removing text from textbox ItemTemplaceSelector uses a wrong template! 2.i want to show every searched item in its parent folder, currently all searched items added into treeview root level.
UPDATE 1:
This is a sample repo App5.zip
First of all change folder path (please create a folder with some sub folders which contains some ttf,otf or woff files. )
await LoadFilesAndFolders(@"D:\Applications\Font");
UPDATE 2:
i used following codes and it seems that everything is working fine.
public void OnAutoSuggestBoxTextChanged(AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args)
{
var query = sender.Text.ToLower();
// Apply filter to the main collection
advancedCollectionView.Filter = item =>
{
var fileSystemItem = item as FileSystemItem;
if (fileSystemItem == null) return false;
return FilterItems(fileSystemItem, query);
};
// Apply filter to children of each item in the main collection
foreach (var item in Items)
{
ApplyFilterToItem(item, query);
}
}
private void ApplyFilterToItem(FileSystemItem item, string query)
{
item.MyChildren.Filter = childItem =>
{
var childFileSystemItem = childItem as FileSystemItem;
if (childFileSystemItem == null) return false;
return FilterItems(childFileSystemItem, query);
};
// Recursively apply the filter to each child
foreach (var child in item.Children)
{
ApplyFilterToItem(child, query);
}
}
bool FilterItems(FileSystemItem item, string query)
{
// Check if the item matches the query
if (item.DisplayName.ToLower().Contains(query))
{
return true;
}
// Recursively check if any child item matches the query
foreach (var child in item.Children)
{
if (FilterItems(child, query))
{
return true;
}
}
return false;
}
Did you mean this?
I make a little change on your code but note OnAutoSuggestBoxTextChanged
need rewriting for the general condition.
I use one more AdvancedCollectionView
for children based on your application design.
public class FileSystemItem
{
...
public ObservableCollection<FileSystemItem> Children { get; } = new ObservableCollection<FileSystemItem>();
public AdvancedCollectionView MyChildren { get; } = new AdvancedCollectionView();
public FileSystemItem(FileSystemInfo fileSystemInfo)
{
...
MyChildren = new AdvancedCollectionView(Children, true);
}
}
XAML
<TreeView x:Name="treeView"
ItemsSource="{x:Bind ViewModel.advancedCollectionView, Mode=OneWay}"
SelectionMode="Multiple">
<TreeView.ItemTemplate>
<DataTemplate x:DataType="local:FileSystemItem">
<TreeViewItem ItemsSource="{x:Bind MyChildren}">
<TextBlock Text="{x:Bind DisplayName}" />
</TreeViewItem>
</DataTemplate>
</TreeView.ItemTemplate>
</TreeView>
The Code behind
public void OnAutoSuggestBoxTextChanged(AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args)
{
advancedCollectionView.Filter = _ => true;
advancedCollectionView.Filter = item =>
{
var node = (FileSystemItem)item;
var name = node.DisplayName ?? "";
// Check if the current node matches the search text
if (name.Contains(sender.Text, StringComparison.OrdinalIgnoreCase))
return true;
if (node.HasChildren)
{
node.MyChildren.Filter = _ => true;
node.MyChildren.Filter = item =>
{
var node = (FileSystemItem)item;
var name = node.DisplayName ?? "";
// Check if the current node matches the search text
if (name.Contains(sender.Text, StringComparison.OrdinalIgnoreCase))
return true;
else
return false;
//TODO rewrite the code. This is Just for example.
};
if (node.MyChildren.Count > 0)
{
return true;
}
}
// Check if any child node matches the search text
//foreach (var child in node.Children)
//{
// if (FilterRecursive(child, sender.Text))
// return true;
//}
// If none of the current node or its children match, return false
return false;
};
}
Update with the more general code example.
private string _theFilterString;
public void OnAutoSuggestBoxTextChanged(AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args)
{
_theFilterString = sender.Text;
advancedCollectionView.Filter = _ => true;
advancedCollectionView.Filter = MyFilter;
}
bool MyFilter(object item)
{
var node = (FileSystemItem)item;
var name = node.DisplayName ?? "";
if (name.Contains(_theFilterString, StringComparison.OrdinalIgnoreCase))
return true;
if (node.HasChildren)
{
node.MyChildren.Filter = _ => true;
node.MyChildren.Filter = MyFilter;
if (node.MyChildren.Count > 0)
{
return true;
}
}
return false;
}