using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Linq; using System.Linq.Expressions; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Media; using System.Windows.Media.Imaging; using InABox.Core; using InABox.WPF; using NPOI.OpenXmlFormats.Dml.Chart; using NPOI.OpenXmlFormats.Dml.Spreadsheet; using Syncfusion.UI.Xaml.TreeGrid; using Syncfusion.Windows.Tools.Controls; namespace InABox.DynamicGrid { public class DynamicTreeNode : INotifyPropertyChanged { private DynamicTreeNodes _owner; public ObservableCollection Children => _owner.GetChilden(_id); private Guid _id; public Guid ID { get { return _id; } set { _id = value; RaisedOnPropertyChanged("ID"); } } private Guid _parent; public Guid Parent { get { return _parent; } set { _parent = value; RaisedOnPropertyChanged("Parent"); } } private string _description; public string Description { get { return _description; } set { _description = value; RaisedOnPropertyChanged("Description"); } } private ImageSource? _image; public ImageSource? Image { get { return _image; } set { _image = value; RaisedOnPropertyChanged("Image"); } } public event PropertyChangedEventHandler? PropertyChanged; public void RaisedOnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } public DynamicTreeNode(DynamicTreeNodes owner) { _owner = owner; _description = ""; } public DynamicTreeNode(DynamicTreeNodes owner, Guid id, Guid parent) : this(owner) { _id = id; _parent = parent; } } public class DynamicTreeNodes { private List _nodes; public ObservableCollection Nodes => new ObservableCollection(_nodes.Where(x => x.Parent == Guid.Empty)); public DynamicTreeNode? this[Guid id] => _nodes.FirstOrDefault(x => x.ID == id); public DynamicTreeNodes() { _nodes = new List(); } public DynamicTreeNode Add(Guid id, Guid parent) { var node = new DynamicTreeNode(this, id, parent); _nodes.Add(node); return node; } public void GetChildren(List nodes, Guid id) { nodes.Add(id); var children = GetChilden(id); foreach (var child in children) GetChildren(nodes, child.ID); } public ObservableCollection GetChilden(Guid id) { return new ObservableCollection(_nodes.Where(x => x.Parent.Equals(id) && (x.ID != id))); } public void Load(CoreTable table, Expression> id, Expression> parentid, Expression> description) { _nodes.Clear(); foreach (var row in table.Rows) { Guid _id = row.Get(id); Guid _parent = row.Get(parentid); String _description = row.Get(description); Add(_id, _parent).Description = _description; } } } public enum DynamicTreeOption { Add, Edit, Delete } public delegate void OnSelectItem(DynamicTreeNode node); public delegate void OnContextMenuOpening(DynamicTreeNode node, ContextMenu menu); public abstract class DynamicTreeView : ContentControl where T : BaseObject, new() { protected abstract Expression> ID { get; } protected abstract Expression> ParentID { get; } protected abstract Expression> Description { get; } public CoreTable Data { get; private set; } private ContextMenu _menu; private SfTreeGrid _tree; private DockPanel _dock; private Grid _grid; private Button _add; private Button _edit; private Button _delete; private Label _spacer; public FluentList Options { get; private set; } public event OnSelectItem OnSelectItem; public event OnContextMenuOpening OnContextMenuOpening; private double minRowHeight = 30D; private double maxRowHeight = 30D; public double MinRowHeight { get => minRowHeight; set { minRowHeight = value; CalculateRowHeight(); } } public double MaxRowHeight { get => maxRowHeight; set { maxRowHeight = value; CalculateRowHeight(); } } /*public double RowHeight { get => _tree.RowHeight; set => _tree.RowHeight = value; }*/ public DynamicTreeView() : base() { Options = new FluentList(); Options.OnChanged += OptionsChanged; _grid = new Grid(); _grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1D, GridUnitType.Star) }); _grid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(1D, GridUnitType.Star) }); _grid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(1D, GridUnitType.Auto) }); _tree = new SfTreeGrid(); _tree.ChildPropertyName = "Children"; //_tree.ParentPropertyName = "Parent"; _tree.AutoGenerateColumns = false; _tree.AutoExpandMode = AutoExpandMode.AllNodesExpanded; //_tree.NodeCollapsing += (o, e) => { e.Cancel = true; }; _tree.HeaderRowHeight = 0D; _tree.SelectionChanged += (o,e) => OnSelectItem?.Invoke((_tree.SelectedItem as DynamicTreeNode)!); _tree.AllowSelectionOnExpanderClick = false; _menu = new ContextMenu(); var additem = new MenuItem() { Header = "Add Child Folder" }; additem.Click += (o, e) => { DoAddItem((_tree.SelectedItem as DynamicTreeNode)!.ID, true); }; _menu.Items.Add(additem); _tree.ContextMenuOpening += _tree_ContextMenuOpening; _tree.ContextMenu = _menu; _tree.Background = new SolidColorBrush(Colors.DimGray); var cellStyle = new Style(typeof(TreeGridRowControl)); cellStyle.Setters.Add(new Setter(BackgroundProperty, new SolidColorBrush(Colors.White))); _tree.RowStyle = cellStyle; _tree.SelectionBackground = new SolidColorBrush(System.Windows.Media.Color.FromArgb(0xFF, 0x11, 0x9E, 0xD9)); _tree.Columns.Add(new TreeGridTextColumn() { MappingName = "Description" } ); _tree.ColumnSizer = TreeColumnSizer.Star; _tree.RowHeight = 30D; _tree.SetValue(Grid.RowProperty, 0); _grid.Children.Add(_tree); _dock = new DockPanel(); _dock.SetValue(Grid.RowProperty, 1); _grid.Children.Add(_dock); _add = CreateButton(Wpf.Resources.add.AsBitmapImage(System.Drawing.Color.White), "", "Add Item", (o) => DoAddItem(Guid.Empty, true)); _add.Margin = new Thickness(0, 2, 2, 0); _add.Visibility = Visibility.Collapsed; _add.SetValue(DockPanel.DockProperty, Dock.Left); _dock.Children.Add(_add); _edit = CreateButton(Wpf.Resources.pencil.AsBitmapImage(System.Drawing.Color.White), "", "Edit Item", EditItem); _edit.Margin = new Thickness(0, 2, 2, 0); _edit.Visibility = Visibility.Collapsed; _edit.SetValue(DockPanel.DockProperty, Dock.Left); _dock.Children.Add(_edit); _delete = CreateButton(Wpf.Resources.delete.AsBitmapImage(System.Drawing.Color.White), "", "Delete Item", DeleteItem); _delete.Margin = new Thickness(2, 2, 0, 0); _delete.Visibility = Visibility.Collapsed; _delete.SetValue(DockPanel.DockProperty, Dock.Right); _dock.Children.Add(_delete); _spacer = new Label(); _spacer.SetValue(DockPanel.DockProperty, Dock.Left); _dock.Children.Add(_spacer); Content = _grid; SizeChanged += DynamicTreeView_SizeChanged; } #region Public Interface public void AddItem(DynamicTreeNode? parentNode = null, bool edit = true) { var id = parentNode?.ID ?? Guid.Empty; DoAddItem(id, edit); } #endregion private void _tree_ContextMenuOpening(object sender, ContextMenuEventArgs e) { _menu.Items.Clear(); if (OnContextMenuOpening is not null) { OnContextMenuOpening.Invoke((_tree.SelectedItem as DynamicTreeNode)!, _menu); if(_menu.Items.Count == 0) { e.Handled = true; } } else { _menu.AddItem("Add Item", null, (_tree.SelectedItem as DynamicTreeNode)!.ID, (id) => DoAddItem(id,true)); } } private void DynamicTreeView_SizeChanged(object sender, SizeChangedEventArgs e) { CalculateRowHeight(); } private void CalculateRowHeight() { if(Data != null && Data.Rows.Count > 0) { var contentHeight = _tree.ActualHeight - (_tree.Padding.Top + _tree.Padding.Bottom) - 2; // Two extra pixels of space var targetHeight = contentHeight / Data.Rows.Count; _tree.RowHeight = Math.Max(Math.Min(targetHeight, MaxRowHeight), MinRowHeight); } } private Button CreateButton(BitmapImage? image = null, string? text = null, string? tooltip = null, Action