| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488 | 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 Syncfusion.UI.Xaml.TreeGrid;using Syncfusion.UI.Xaml.TreeView;using Syncfusion.Windows.Tools.Controls;namespace InABox.DynamicGrid{    public class DynamicTreeNode : INotifyPropertyChanged    {        private DynamicTreeNodes _owner;                public ObservableCollection<DynamicTreeNode> 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<DynamicTreeNode> _nodes;        public ObservableCollection<DynamicTreeNode> Nodes => new ObservableCollection<DynamicTreeNode>(_nodes.Where(x => x.Parent == Guid.Empty));                public DynamicTreeNodes()        {            _nodes = new List<DynamicTreeNode>();        }        public DynamicTreeNode Add(Guid id, Guid parent)        {            var node = new DynamicTreeNode(this, id, parent);            _nodes.Add(node);            return node;        }        public ObservableCollection<DynamicTreeNode> GetChilden(Guid id)        {            return new ObservableCollection<DynamicTreeNode>(_nodes.Where(x => x.Parent.Equals(id) && (x.ID != id)));        }        public void Load<T>(CoreTable table, Expression<Func<T, Guid>> id, Expression<Func<T, Guid>> parentid, Expression<Func<T, String>> description)        {            _nodes.Clear();            foreach (var row in table.Rows)            {                Guid _id = row.Get<T, Guid>(id);                Guid _parent = row.Get<T, Guid>(parentid);                String _description = row.Get<T, String>(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<T> : ContentControl where T : BaseObject, new()    {        protected abstract Expression<Func<T, Guid>> ID { get; }        protected abstract Expression<Func<T, Guid>> ParentID { get; }        protected abstract Expression<Func<T, String>> Description { get; }        protected 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<DynamicTreeOption> 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<DynamicTreeOption>();            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) => { AddItem((_tree.SelectedItem as DynamicTreeNode)!.ID); };            _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(Properties.Resources.add.AsBitmapImage(System.Drawing.Color.White), "", "Add Item", (o) => AddItem(Guid.Empty));            _add.Margin = new Thickness(0, 2, 2, 0);            _add.Visibility = Visibility.Collapsed;            _add.SetValue(DockPanel.DockProperty, Dock.Left);            _dock.Children.Add(_add);                        _edit = CreateButton(Properties.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(Properties.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;            try            {                T item = DoCreateItem(id);                if (edit)                {                    if (DoEditItem(item))                    {                        DoSaveItem(item);                        Refresh();                    }                }                else                {                    DoSaveItem(item);                    Refresh();                }            }            catch (Exception e)            {                MessageBox.Show(e.Message);            }        }        #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, AddItem);            }        }        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<Button>? action = null)        {            var button = new Button();            button.SetValue(BorderBrushProperty, new SolidColorBrush(Colors.Gray));            button.SetValue(BorderThicknessProperty, new Thickness(0.75));            button.Height = 30;            button.MinWidth = 30;            button.Click += (o, e) => action?.Invoke(button);            UpdateButton(button, image, text, tooltip);            return button;        }        protected void UpdateButton(Button button, BitmapImage? image, string? text, string? tooltip = null)        {            var stackPnl = new StackPanel();            stackPnl.Orientation = Orientation.Horizontal;            if (image != null)            {                var img = new Image();                img.Source = image;                img.Margin = new Thickness(2);                img.ToolTip = tooltip;                stackPnl.Children.Add(img);            }            if (!string.IsNullOrEmpty(text))            {                var lbl = new Label();                lbl.Content = text;                lbl.VerticalAlignment = VerticalAlignment.Stretch;                lbl.VerticalContentAlignment = VerticalAlignment.Center;                lbl.Margin = new Thickness(2, 0, 5, 0);                lbl.ToolTip = ToolTip;                stackPnl.Children.Add(lbl);            }            button.Content = stackPnl;            button.ToolTip = tooltip;        }                private void OptionsChanged(object sender, EventArgs args)        {            _add.Visibility = Options.Contains(DynamicTreeOption.Add) ? Visibility.Visible : Visibility.Collapsed;            _edit.Visibility = Options.Contains(DynamicTreeOption.Edit) ? Visibility.Visible : Visibility.Collapsed;            _delete.Visibility = Options.Contains(DynamicTreeOption.Delete) ? Visibility.Visible : Visibility.Collapsed;        }        protected virtual T DoCreateItem(Guid parent)        {            T result = new T();            CoreUtils.SetPropertyValue(result, CoreUtils.GetFullPropertyName(ParentID, "."), parent);            return result;        }        protected abstract T? DoLoadItem(Guid id);        protected virtual bool DoEditItem(T item)        {            var form = new DynamicEditorForm(typeof(T));            form.Items = new T[] { item };            return form.ShowDialog() == true;        }        protected abstract void DoSaveItem(T item);        protected abstract bool DoDeleteItem(Guid id);        private void AddItem(Guid id)        {            try            {                T item = DoCreateItem(id);                if (DoEditItem(item))                {                    DoSaveItem(item);                    Refresh();                }            }            catch (Exception e)            {                MessageBox.Show(e.Message);            }        }                private void EditItem(Button button)        {            var node = _tree.SelectedItem as DynamicTreeNode;            if (node == null)            {                MessageBox.Show("Please Select an item to edit!");                return;            }            var item = DoLoadItem(node.ID);            if (item != null && DoEditItem(item))            {                DoSaveItem(item);                Refresh();            }        }        private  void DeleteItem(Button button)        {            var node = _tree.SelectedItem as DynamicTreeNode;            if (node == null)            {                MessageBox.Show("Please Select an item to edit!");                return;            }            if (DoDeleteItem(node.ID))            {                Refresh();            }        }                public DynamicTreeNodes Nodes { get; set; }        protected abstract void DoRefresh(Action<CoreTable?, Exception?> action);        private void AfterRefresh()        {            var nodes = new DynamicTreeNodes();            foreach (var row in Data.Rows)            {                var _id = row.Get(ID);                var _parent = row.Get(ParentID);                var _description = row.Get(Description);                nodes.Add(_id, _parent).Description = _description;            }            Nodes = nodes;            _tree.ItemsSource = nodes.Nodes;            CalculateRowHeight();        }        public void Refresh()        {            DoRefresh((table, exception) =>            {                if(exception != null)                {                    Dispatcher.Invoke(() =>                    {                        MessageBox.Show(String.Format("Error: {0}", exception.Message));                    });                }                else if(table is not null)                {                    Data = table;                    Dispatcher.Invoke(() =>                    {                        AfterRefresh();                    });                }            });        }    }}
 |