using InABox.Core; using InABox.WPF; using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Media; namespace InABox.DynamicGrid; public abstract class CheckBoxDynamicGridColumnFilter : IDynamicGridColumnFilter { protected HashSet? SelectedFilters = null; private FilterItem[] _items = []; private FilterItem _selectAll; public event Action? FilterChanged; public CheckBoxDynamicGridColumnFilter() { _selectAll = new(new(), "Select All", this); } #region Abstract Interface protected abstract FilterItem[] GetData(); public abstract bool FilterRow(CoreRow row); #endregion protected class FilterItem(object? value, string display, CheckBoxDynamicGridColumnFilter parent) : INotifyPropertyChanged { private object? _value = value; public object? Value { get => _value; set { _value = value; OnPropertyChanged(); } } private string _display = display; public string Display { get => _display; set { _display = value; OnPropertyChanged(); } } public bool IsChecked { get => this == parent._selectAll ? (parent.SelectedFilters is null) : (parent.SelectedFilters is null || parent.SelectedFilters.Contains(Value)); } public event PropertyChangedEventHandler? PropertyChanged; private void OnPropertyChanged([CallerMemberName] string propertyName = "") { PropertyChanged?.Invoke(this, new(propertyName)); } public void UpdateChecked() { OnPropertyChanged(nameof(IsChecked)); } } public FrameworkElement CreateControl() { var grid = new Grid(); grid.AddRow(GridUnitType.Auto); grid.AddRow(GridUnitType.Star); var searchBox = new TextBox { Background = Colors.LightYellow.ToBrush(), Margin = new(0.0, 0.0, 0.0, 5.0), Padding = new(5.0), VerticalContentAlignment = VerticalAlignment.Center }; new TextBoxPlaceholderBehaviour { Text = "Search..." }.Attach(searchBox); _items = GetData(); var itemList = new ListBox { Margin = new(0.0, 0.0, 0.0, 0.0) }; itemList.ItemTemplate = TemplateGenerator.CreateDataTemplate(() => { var box = new CheckBox(); box.Height = 25; box.VerticalAlignment = VerticalAlignment.Center; box.VerticalContentAlignment = VerticalAlignment.Center; box.HorizontalAlignment = HorizontalAlignment.Stretch; box.Bind( CheckBox.ContentProperty, x => x.Display, mode: BindingMode.OneWay); box.Bind( CheckBox.IsCheckedProperty, x => x.IsChecked, mode: BindingMode.OneWay); box.Bind(CheckBox.TagProperty, x => x); box.Checked += Box_Checked; box.Unchecked += Box_Unchecked; return box; }); itemList.HorizontalContentAlignment = HorizontalAlignment.Stretch; itemList.VerticalContentAlignment = VerticalAlignment.Center; itemList.ItemsSource = CoreUtils.One(_selectAll).Concat(_items); searchBox.TextChanged += (o, e) => { itemList.ItemsSource = CoreUtils.One(_selectAll) .Concat(_items.Where(x => x.Display.Contains(searchBox.Text, StringComparison.CurrentCultureIgnoreCase))); }; grid.AddChild(searchBox, 0, 0); grid.AddChild(itemList, 1, 0); return grid; } private bool _updating = false; private void Box_Unchecked(object sender, RoutedEventArgs e) { if (_updating || sender is not CheckBox box || box.Tag is not FilterItem tag) return; if(box.Tag == _selectAll) { if(SelectedFilters is null || SelectedFilters.Count > 0) { SelectedFilters = new(); _updating = true; foreach(var item in _items) { item.UpdateChecked(); } _selectAll.UpdateChecked(); _updating = false; FilterChanged?.Invoke(this); } } else { if(SelectedFilters is null) { SelectedFilters = _items.Select(x => x.Value).ToHashSet(); SelectedFilters.Remove(tag.Value); _updating = true; tag.UpdateChecked(); _selectAll.UpdateChecked(); _updating = false; FilterChanged?.Invoke(this); } else if(SelectedFilters.Remove(tag.Value)) { _updating = true; tag.UpdateChecked(); _selectAll.UpdateChecked(); _updating = false; FilterChanged?.Invoke(this); } } } private void Box_Checked(object sender, RoutedEventArgs e) { if (_updating || sender is not CheckBox box || box.Tag is not FilterItem tag) return; if(tag == _selectAll) { if(SelectedFilters is not null) { SelectedFilters = null; _updating = true; foreach(var item in _items) { item.UpdateChecked(); } _selectAll.UpdateChecked(); _updating = false; FilterChanged?.Invoke(this); } } else { if(SelectedFilters is not null && SelectedFilters.Add(tag.Value)) { _updating = true; tag.UpdateChecked(); _updating = false; FilterChanged?.Invoke(this); } } } public void ClearFilter() { if(SelectedFilters is null) { return; } SelectedFilters = null; _updating = true; foreach(var item in _items) { item.UpdateChecked(); } _selectAll.UpdateChecked(); _updating = false; FilterChanged?.Invoke(this); } public bool IsFiltered() { return SelectedFilters is not null; } } public class FuncCheckBoxDynamicGridColumnFilter( Func, bool> filter, Func>> data) : CheckBoxDynamicGridColumnFilter { protected override FilterItem[] GetData() { return data().Select(x => new FilterItem(x.Item2, x.Item1, this)).ToArray(); } public override bool FilterRow(CoreRow row) { return filter(row, x => SelectedFilters is null || SelectedFilters.Contains(x)); } } public class StaticColumnFilter( Func rowData, Tuple[] data) : CheckBoxDynamicGridColumnFilter { protected override FilterItem[] GetData() { return data.ToArray(x => new FilterItem(x.Item2, x.Item1, this)); } public override bool FilterRow(CoreRow row) { return SelectedFilters is null || SelectedFilters.Contains(rowData(row)); } } public class DynamicColumnFilter( Func rowData, Func, IEnumerable>> data) : CheckBoxDynamicGridColumnFilter { protected override FilterItem[] GetData() { return data(this).Select(x => new FilterItem(x.Item2, x.Item1, this)).ToArray(); } public override bool FilterRow(CoreRow row) { return SelectedFilters is null || SelectedFilters.Contains(rowData(row)); } }