using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Linq; using System.Linq.Expressions; using System.Windows; using System.Windows.Controls; using System.Windows.Media; using System.Windows.Media.Imaging; using InABox.Core; using InABox.WPF; using Syncfusion.UI.Xaml.Grid; using Syncfusion.UI.Xaml.TreeGrid; namespace InABox.DynamicGrid { public enum DynamicTreeOption { Add, Edit, Delete } public enum DynamicTreeGridLines { Both, Horizontal, Vertical, None } public enum DynamicTreeGridExpandMode { All, Root, None } public delegate void OnSelectItem(CoreTreeNode node); public delegate void OnContextMenuOpening(CoreTreeNode 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(); } } private bool _shownumbers = false; public bool ShowNumbers { get => _shownumbers; set { _shownumbers = value; _tree.Columns[1].Width = value ? 50 : 0; } } private DynamicTreeGridLines _gridLines = DynamicTreeGridLines.Both; public DynamicTreeGridLines GridLines { get => _gridLines; set { _gridLines = value; _tree.GridLinesVisibility = value switch { DynamicTreeGridLines.Both => GridLinesVisibility.Both, DynamicTreeGridLines.Horizontal => GridLinesVisibility.Horizontal, DynamicTreeGridLines.Vertical => GridLinesVisibility.Vertical, _ => GridLinesVisibility.None }; } } public DynamicTreeGridExpandMode ExpandMode { get { return _tree.AutoExpandMode switch { AutoExpandMode.AllNodesExpanded => DynamicTreeGridExpandMode.All, AutoExpandMode.RootNodesExpanded => DynamicTreeGridExpandMode.Root, _ => DynamicTreeGridExpandMode.None }; } set { _tree.AutoExpandMode = value switch { DynamicTreeGridExpandMode.All => AutoExpandMode.AllNodesExpanded, DynamicTreeGridExpandMode.Root => AutoExpandMode.RootNodesExpanded, _ => AutoExpandMode.None }; } } public Guid SelectedID => (_tree?.SelectedItem as CoreTreeNode)?.ID ?? Guid.Empty; /*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.NodeCollapsing += (o, e) => { e.Cancel = true; }; _tree.HeaderRowHeight = 0D; _tree.SelectionChanged += (o,e) => OnSelectItem?.Invoke((_tree.SelectedItem as CoreTreeNode)!); _tree.AllowSelectionOnExpanderClick = false; ExpandMode = DynamicTreeGridExpandMode.All; _menu = new ContextMenu(); //var additem = new MenuItem() { Header = "Add Child Folder" }; //additem.Click += (o, e) => { DoAddItem((_tree.SelectedItem as CoreTreeNode)!.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.Columns.Add(new TreeGridTextColumn() { MappingName = "Number", Width = _shownumbers ? 50 : 0, TextAlignment = TextAlignment.Right } ); _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(CoreTreeNode? 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 CoreTreeNode)!, _menu); if(_menu.Items.Count == 0) { e.Handled = true; } } else { if (Options.Contains(DynamicTreeOption.Add)) { _menu.AddItem("Add Item", null, (_tree.SelectedItem as CoreTreeNode)!.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