I'm working on getting a UserControl in WPF working that has a MenuItem populated with an ItemsSource, which creates a menu that goes n levels deep (although I'm just looking at TopMenuItem\Branches\Leaves right now). The wrinkle I'm having trouble with is that I want to filter the leaves through a textbox embedded into the menu. If a branch has no leaves, it also gets filtered out. It looks like this at the moment :
I'm working with an ObservableCollection of IMenuTreeItem, which can contain branches (which in turn also has an ObservableCollection of IMenuTreeItem) or leaves.
public interface IMenuTreeItem
{
string Name { get; set; }
}
public class MenuTreeLeaf : IMenuTreeItem
{
public string Name { get; set; }
public Guid UID { get; set; }
public ObjectType Type { get; set; }
public Requirement Requirement { get; set; }
public MenuTreeLeaf(string name, ObjectType type, Guid uID)
{
Type = type;
Name = name;
UID = uID;
}
public MenuTreeLeaf(string name)
{
Name = name;
}
}
public class MenuTreeBranch : IMenuTreeItem, INotifyPropertyChanged
{
public string Name { get; set; }
private ObservableCollection<IMenuTreeItem> _items;
public ObservableCollection<IMenuTreeItem> Items
{
get
{
return _items;
}
set
{
_items = value; OnPropertyChanged();
}
}
public MenuTreeBranch(string name)
{
Name = name;
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
This is how I'm filtering. It very much feels like there's a better way.
ObservableCollection<IMenuTreeItem> result = new ObservableCollection<IMenuTreeItem>(ItemsSource);
for (int i = 0; i < result.Count; i++)
{
if (result[i] is MenuTreeBranch currentBranch)
{
if (currentBranch.Items != null)
currentBranch.Items = new ObservableCollection<IMenuTreeItem>(currentBranch.Items.Where(x => x.Name.ToLower().Contains(SearchField.ToLower())));
}
}
result = new ObservableCollection<IMenuTreeItem>(result.Where(x => (x as MenuTreeBranch).Items.Count > 0));
result.Insert(0, new MenuTreeLeaf("[Search]"));
return result;
So my main problems are:
- When I've filtered, I can no longer unfilter. ItemsSource gets changed too. Could it be because I'm filtering in the ItemsSourceFiltered getter? I tried to clone, but eh, didn't change anything
- When I call OnPropertyChanged on ItemsSourceFiltered any time text changes in the textbox, the menu closes. The menu definitely shouldn't close while you're inputting text.
Any advice?