Parcourir la source

Fixing data mappings and various bugs.

Kenric Nugteren il y a 1 an
Parent
commit
50be6deb6e

+ 10 - 0
InABox.Core/CoreTreeNodes.cs

@@ -69,6 +69,11 @@ namespace InABox.Core
             }
         }
 
+        public object? this[string column]
+        {
+            get => Row[column];
+        }
+
         public event PropertyChangedEventHandler? PropertyChanged;
 
         public void RaisedOnPropertyChanged(string propertyName)
@@ -99,6 +104,11 @@ namespace InABox.Core
                 : _owner.Nodes.IndexOf(this) + 1;
         }
 
+        public void InvalidateData()
+        {
+            RaisedOnPropertyChanged("Row");
+        }
+
         public String Number
         {
             get

+ 11 - 11
inabox.wpf/DynamicGrid/Columns/EditorColumns/DynamicGridCheckBoxColumn.cs

@@ -21,7 +21,7 @@ public class DynamicGridCheckBoxColumn<TEntity> : DynamicGridEditorColumn<TEntit
     private readonly BitmapImage ticked = Wpf.Resources.Bullet_Tick.AsBitmapImage();
     private readonly BitmapImage unticked = null; //Wpf.Resources.tick.AsGrayScale().AsBitmapImage();
 
-    private DataTemplate CreateCellTemplate()
+    private DataTemplate CreateCellTemplate(string mapping)
     {
         return TemplateGenerator.CreateDataTemplate
         (
@@ -32,7 +32,7 @@ public class DynamicGridCheckBoxColumn<TEntity> : DynamicGridEditorColumn<TEntit
                     Image.SourceProperty, 
                     new Binding()
                     {
-                        Path = new PropertyPath(MappingName), 
+                        Path = new PropertyPath(mapping), 
                         Converter = new BoolToImageConverter()
                     }
                 );
@@ -40,15 +40,15 @@ public class DynamicGridCheckBoxColumn<TEntity> : DynamicGridEditorColumn<TEntit
             }
         );
     }
-    private DataTemplate CreateEditTemplate()
+    private DataTemplate CreateEditTemplate(string mapping)
     {
         return TemplateGenerator.CreateDataTemplate
         (
             () =>
             {
                 DockPanel dock = new DockPanel();
-                dock.Children.Add(CreateImage(ticked, Visibility.Visible, Visibility.Collapsed, BindingMode.TwoWay));
-                dock.Children.Add(CreateImage(unticked, Visibility.Collapsed, Visibility.Visible, BindingMode.TwoWay));
+                dock.Children.Add(CreateImage(mapping, ticked, Visibility.Visible, Visibility.Collapsed, BindingMode.TwoWay));
+                dock.Children.Add(CreateImage(mapping, unticked, Visibility.Collapsed, Visibility.Visible, BindingMode.TwoWay));
                 Border border = new Border()
                 {
                     Background = new SolidColorBrush(Colors.White),
@@ -75,14 +75,14 @@ public class DynamicGridCheckBoxColumn<TEntity> : DynamicGridEditorColumn<TEntit
     
     protected override void Configure(GridTemplateColumn column, CheckBoxEditor editor)
     {
-        column.CellTemplate = CreateCellTemplate();
-        column.EditTemplate = CreateEditTemplate();
+        column.CellTemplate = CreateCellTemplate(MappingName);
+        column.EditTemplate = CreateEditTemplate(MappingName);
         column.SetCellBoundValue = false;
     }
     protected override void Configure(TreeGridTemplateColumn column, CheckBoxEditor editor)
     {
-        column.CellTemplate = CreateCellTemplate();
-        column.EditTemplate = CreateEditTemplate();
+        column.CellTemplate = CreateCellTemplate(TreeMappingName);
+        column.EditTemplate = CreateEditTemplate(TreeMappingName);
         column.SetCellBoundValue = false;
     }
 
@@ -98,7 +98,7 @@ public class DynamicGridCheckBoxColumn<TEntity> : DynamicGridEditorColumn<TEntit
             : Visibility.Visible;
     }
 
-    private Image CreateImage(BitmapImage source, Visibility truevalue, Visibility falsevalue, BindingMode mode)
+    private Image CreateImage(string mapping, BitmapImage source, Visibility truevalue, Visibility falsevalue, BindingMode mode)
     {
         var image = new Image() { Source = source, Margin = new Thickness(2) };
         image.SetValue(DockPanel.DockProperty,Dock.Top);
@@ -106,7 +106,7 @@ public class DynamicGridCheckBoxColumn<TEntity> : DynamicGridEditorColumn<TEntit
             Image.VisibilityProperty, 
             new Binding()
             {
-                Path = new PropertyPath(MappingName), 
+                Path = new PropertyPath(mapping), 
                 Converter = new WPF.BooleanToVisibilityConverter() { TrueValue = truevalue, FalseValue = falsevalue }, 
                 Mode = mode
             }

+ 8 - 8
inabox.wpf/DynamicGrid/Columns/EditorColumns/DynamicGridCodeColumn.cs

@@ -14,17 +14,17 @@ public class DynamicGridCodeColumn<TEntity> : DynamicGridEditorColumn<TEntity, C
 {
     protected override void Configure(GridTemplateColumn column, CodeEditor editor)
     {
-        column.CellTemplate = CreateCellTemplate(editor);
-        column.EditTemplate = CreateEditTemplate(editor, column);
+        column.CellTemplate = CreateCellTemplate(editor, MappingName);
+        column.EditTemplate = CreateEditTemplate(editor, column, MappingName);
     }
 
     protected override void Configure(TreeGridTemplateColumn column, CodeEditor editor)
     {
-        column.CellTemplate = CreateCellTemplate(editor);
-        column.EditTemplate = CreateEditTemplate(editor, column);
+        column.CellTemplate = CreateCellTemplate(editor, TreeMappingName);
+        column.EditTemplate = CreateEditTemplate(editor, column, TreeMappingName);
     }
 
-    private DataTemplate CreateCellTemplate(CodeEditor editor)
+    private DataTemplate CreateCellTemplate(CodeEditor editor, string mapping)
     {
         return TemplateGenerator.CreateDataTemplate
         (
@@ -35,7 +35,7 @@ public class DynamicGridCodeColumn<TEntity> : DynamicGridEditorColumn<TEntity, C
                 result.VerticalContentAlignment = GetVerticalAlignment(editor);
                 var binding = new Binding()
                 {
-                    Path = new PropertyPath(MappingName),
+                    Path = new PropertyPath(mapping),
                 };
                 result.SetBinding(Label.ContentProperty, binding);
                 return result;
@@ -43,7 +43,7 @@ public class DynamicGridCodeColumn<TEntity> : DynamicGridEditorColumn<TEntity, C
         );
     }
 
-    private DataTemplate CreateEditTemplate(CodeEditor editor, GridColumnBase column)
+    private DataTemplate CreateEditTemplate(CodeEditor editor, GridColumnBase column, string mapping)
     {
         return TemplateGenerator.CreateDataTemplate
         (
@@ -54,7 +54,7 @@ public class DynamicGridCodeColumn<TEntity> : DynamicGridEditorColumn<TEntity, C
                 textbox.TextAlignment = column.TextAlignment;
                 textbox.SetBinding(TextBox.TextProperty, new Binding()
                 {
-                    Path = new PropertyPath(MappingName)
+                    Path = new PropertyPath(mapping)
                 });
                 
                 textbox.SetValue(Grid.ColumnSpanProperty, 2);

+ 4 - 4
inabox.wpf/DynamicGrid/Columns/EditorColumns/DynamicGridColorColumn.cs

@@ -19,14 +19,14 @@ public class DynamicGridColorColumn<TEntity> : DynamicGridEditorColumn<TEntity,
     
     protected override void UpdateBinding(GridImageColumn column)
     {
-        column.ValueBinding = GetBinding();
+        column.ValueBinding = GetBinding(MappingName);
     }
 
-    private Binding GetBinding()
+    private Binding GetBinding(string mapping)
     {
         return new Binding
         {
-            Path = new PropertyPath(MappingName),
+            Path = new PropertyPath(mapping),
             Converter = new StringToColorImageConverter(Math.Max(25,_width) - 8, Math.Max(25,_height) - 8)
         };
     }
@@ -50,7 +50,7 @@ public class DynamicGridColorColumn<TEntity> : DynamicGridEditorColumn<TEntity,
                 Height = Math.Max(25, _height) - 8,
                 Width = Math.Max(25, _width) - 8
             };
-            image.SetBinding(Image.SourceProperty, GetBinding());
+            image.SetBinding(Image.SourceProperty, GetBinding(TreeMappingName));
             return image;
         });
     }

+ 3 - 1
inabox.wpf/DynamicGrid/Columns/EditorColumns/DynamicGridEditorColumn.cs

@@ -20,6 +20,8 @@ public abstract class DynamicGridEditorColumn<TEntity, TEditor, TGridColumn, TTr
     public List<string> ExtraColumns { get; } = new();
     
     public string? MappingName => Definition?.ColumnName.Replace('.', '_');
+
+    public string? TreeMappingName => $"[{Definition?.ColumnName}]";
     
     public Func<BaseObject>? GetEntity { get; set; }
     
@@ -103,7 +105,7 @@ public abstract class DynamicGridEditorColumn<TEntity, TEditor, TGridColumn, TTr
     }
     protected virtual void UpdateBinding(TTreeColumn column)
     {
-        column.MappingName = MappingName;
+        column.MappingName = TreeMappingName;
     }
 
     protected TextAlignment GetTextAlignment(TEditor editor) => Definition?.Alignment == Alignment.NotSet

+ 5 - 5
inabox.wpf/DynamicGrid/Columns/EditorColumns/DynamicGridMaskColumn.cs

@@ -57,7 +57,7 @@ public abstract class DynamicGridMaskColumn<TEntity, TEditor> : DynamicGridEdito
 
     protected abstract IValueConverter? CreateConverter();
 
-    protected virtual Tuple<DataTemplate, DataTemplate> CreateTemplates(GridColumnBase column, TEditor editor)
+    protected virtual Tuple<DataTemplate, DataTemplate> CreateTemplates(GridColumnBase column, TEditor editor, string mapping)
     {
         var converter = CreateConverter();
         var cellTemplate = TemplateGenerator.CreateDataTemplate
@@ -75,7 +75,7 @@ public abstract class DynamicGridMaskColumn<TEntity, TEditor> : DynamicGridEdito
                 };
                 var binding = new Binding()
                 {
-                    Path = new PropertyPath(MappingName),
+                    Path = new PropertyPath(mapping),
                     Converter = converter
                 };
                 result.SetBinding(Label.ContentProperty, binding);
@@ -111,7 +111,7 @@ public abstract class DynamicGridMaskColumn<TEntity, TEditor> : DynamicGridEdito
                 
                 textbox.SetBinding(TextBox.TextProperty, new Binding()
                 {
-                    Path = new PropertyPath(MappingName),
+                    Path = new PropertyPath(mapping),
                     Converter = converter,
                     NotifyOnSourceUpdated = true,
                     NotifyOnTargetUpdated = true,
@@ -170,7 +170,7 @@ public abstract class DynamicGridMaskColumn<TEntity, TEditor> : DynamicGridEdito
     
     protected override void Configure(GridTemplateColumn column, TEditor editor)
     {
-        var (cellTemplate, editTemplate) = CreateTemplates(column, editor);
+        var (cellTemplate, editTemplate) = CreateTemplates(column, editor, MappingName);
         column.CellTemplate = cellTemplate;
         column.EditTemplate = editTemplate;
         
@@ -178,7 +178,7 @@ public abstract class DynamicGridMaskColumn<TEntity, TEditor> : DynamicGridEdito
     }
     protected override void Configure(TreeGridTemplateColumn column, TEditor editor)
     {
-        var (cellTemplate, editTemplate) = CreateTemplates(column, editor);
+        var (cellTemplate, editTemplate) = CreateTemplates(column, editor, TreeMappingName);
         column.CellTemplate = cellTemplate;
         column.EditTemplate = editTemplate;
         

+ 4 - 4
inabox.wpf/DynamicGrid/Columns/EditorColumns/DynamicGridMemoColumn.cs

@@ -11,12 +11,12 @@ namespace InABox.DynamicGrid;
 public class DynamicGridMemoColumn<TEntity> : DynamicGridEditorColumn<TEntity, MemoEditor, GridTextColumn, TreeGridTextColumn>
     where TEntity : BaseObject
 {
-    private void UpdateBinding(GridColumnBase column)
+    private void UpdateBinding(GridColumnBase column, string mapping)
     {
         var prop = CoreUtils.GetProperty<TEntity>(Definition.ColumnName);
         var binding = new Binding
         {
-            Path = new PropertyPath(MappingName), 
+            Path = new PropertyPath(mapping), 
             Converter = prop.PropertyType == typeof(string[]) 
                 ? new StringArrayConverter() 
                 : null
@@ -29,13 +29,13 @@ public class DynamicGridMemoColumn<TEntity> : DynamicGridEditorColumn<TEntity, M
     protected override void UpdateBinding(GridTextColumn column)
     {
         base.UpdateBinding(column);
-        UpdateBinding(column);
+        UpdateBinding(column, MappingName);
     }
 
     protected override void UpdateBinding(TreeGridTextColumn column)
     {
         base.UpdateBinding(column);
-        UpdateBinding(column);
+        UpdateBinding(column, TreeMappingName);
     }
 
     protected override void Configure(GridTextColumn column, MemoEditor editor)

+ 5 - 5
inabox.wpf/DynamicGrid/Columns/EditorColumns/DynamicGridUniqueCodeColumn.cs

@@ -13,7 +13,7 @@ public class DynamicGridUniqueCodeColumn<TEntity> : DynamicGridEditorColumn<TEnt
 {
 
 
-    private Tuple<DataTemplate, DataTemplate> GetTemplates(GridColumnBase column, UniqueCodeEditor editor)
+    private Tuple<DataTemplate, DataTemplate> GetTemplates(GridColumnBase column, UniqueCodeEditor editor, string mapping)
     {
         var cell = TemplateGenerator.CreateDataTemplate
         (
@@ -27,7 +27,7 @@ public class DynamicGridUniqueCodeColumn<TEntity> : DynamicGridEditorColumn<TEnt
                         : HorizontalAlignment.Right;
                 var binding = new Binding()
                 {
-                    Path = new PropertyPath(MappingName),
+                    Path = new PropertyPath(mapping),
                 };
                 result.SetBinding(Label.ContentProperty, binding);
                 return result;
@@ -43,7 +43,7 @@ public class DynamicGridUniqueCodeColumn<TEntity> : DynamicGridEditorColumn<TEnt
                 textbox.TextAlignment = column.TextAlignment;
                 textbox.SetBinding(TextBox.TextProperty, new Binding()
                 {
-                    Path = new PropertyPath(MappingName)
+                    Path = new PropertyPath(mapping)
                 });
                 
                 textbox.SetValue(Grid.ColumnSpanProperty, 2);
@@ -68,14 +68,14 @@ public class DynamicGridUniqueCodeColumn<TEntity> : DynamicGridEditorColumn<TEnt
 
     protected override void Configure(TreeGridTemplateColumn column, UniqueCodeEditor editor)
     {
-        var (cell, edit) = GetTemplates(column, editor);
+        var (cell, edit) = GetTemplates(column, editor, TreeMappingName);
         column.CellTemplate = cell;
         column.EditTemplate = edit;
     }
 
     protected override void Configure(GridTemplateColumn column, UniqueCodeEditor editor)
     {
-        var (cell, edit) = GetTemplates(column, editor);
+        var (cell, edit) = GetTemplates(column, editor, MappingName);
         column.CellTemplate = cell;
         column.EditTemplate = edit;
     }

+ 1 - 0
inabox.wpf/DynamicGrid/Columns/EditorColumns/IDynamicGridEditorColumn.cs

@@ -10,6 +10,7 @@ public interface IDynamicGridEditorColumn : IDynamicColumnBase
 {
     DynamicGridColumn? Definition { get; set; }
     string? MappingName { get; }
+    string? TreeMappingName { get; }
     List<string> ExtraColumns { get; }
 
     bool VariableWidth { get; }

+ 121 - 31
inabox.wpf/DynamicGrid/UIComponent/DynamicGridTreeUIComponent.cs

@@ -19,6 +19,7 @@ using System.Windows.Controls;
 using System.Windows.Data;
 using System.Windows.Input;
 using System.Windows.Media;
+using System.Windows.Media.Imaging;
 
 namespace InABox.DynamicGrid;
 
@@ -53,8 +54,6 @@ public class DynamicGridTreeUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
     private SfTreeGrid _tree;
     private readonly ContextMenu ColumnsMenu;
 
-    private Dictionary<Guid, CoreRow>? _rowMap;
-
     public event OnContextMenuOpening OnContextMenuOpening;
 
     FrameworkElement IDynamicGridUIComponent<T>.Control => _tree;
@@ -129,12 +128,15 @@ public class DynamicGridTreeUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
         _tree.AutoExpandMode = AutoExpandMode.AllNodesExpanded;
         //_tree.NodeCollapsing += (o, e) => { e.Cancel = true; };
         //_tree.HeaderRowHeight = 0D;
+        _tree.HeaderRowHeight = 30;
         _tree.HeaderContextMenu = ColumnsMenu;
 
         _tree.SelectionChanging += _tree_SelectionChanging;
         _tree.SelectionChanged += _tree_SelectionChanged;
         _tree.AllowSelectionOnExpanderClick = false;
 
+        _tree.AllowAutoSizingExpanderColumn = false;
+
         _tree.CellTapped += _tree_CellTapped;
         _tree.CellDoubleTapped += _tree_CellDoubleTapped;
         _tree.KeyUp += _tree_KeyUp;
@@ -160,10 +162,24 @@ public class DynamicGridTreeUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
         _tree.SelectionForeground = DynamicGridUtils.SelectionForeground;
         _tree.SelectionBackground = DynamicGridUtils.SelectionBackground;
         
-        _tree.ColumnSizer = TreeColumnSizer.Star;
+        _tree.ColumnSizer = TreeColumnSizer.None;
         _tree.RowHeight = 30D;
         _tree.SetValue(Grid.RowProperty, 0);
 
+        _tree.AllowDraggingRows = false;
+        _tree.Drop += _tree_Drop;
+        _tree.DragOver += _tree_DragOver;
+        _tree.RowDragDropTemplate = TemplateGenerator.CreateDataTemplate(() =>
+        {
+            var border = new Border();
+            border.Width = 100;
+            border.Height = 100;
+            border.BorderBrush = new SolidColorBrush(Colors.Firebrick);
+            border.Background = new SolidColorBrush(Colors.Red);
+            border.CornerRadius = new CornerRadius(5);
+            return border;
+        });
+
         _tree.SizeChanged += _tree_SizeChanged;
     }
 
@@ -171,7 +187,7 @@ public class DynamicGridTreeUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
 
     public IEnumerable<CoreRow> GetChildren(Guid id)
     {
-        return Nodes.GetChildren(id).Select(x => x.Row);
+        return Nodes.GetChildren(id).Select(x => MapRow(x.Row));
     }
 
     #endregion
@@ -183,7 +199,7 @@ public class DynamicGridTreeUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
         // Syncfusion has given us the row index, so it also will give us the correct row, after sorting.
         // Hence, here we use the syncfusion DataGrid.GetRecordAtRowIndex, which *should* always return a DataRowView.
         var row = _tree.GetNodeAtRowIndex(rowIndex);
-        return (row.Item as CoreTreeNode)?.Row;
+        return MapRow((row.Item as CoreTreeNode)?.Row);
     }
 
     private void _tree_CellDoubleTapped(object? sender, TreeGridCellDoubleTappedEventArgs e)
@@ -191,7 +207,7 @@ public class DynamicGridTreeUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
         _tree.Dispatcher.BeginInvoke(() =>
         {
             // This needs to happen outside the event handler, because the items source for the tree view might change during this method, and that causes an internal exception in Syncfusion. We need to finish the event before resetting the items source.
-        Parent.DoubleClickCell(GetRowFromIndex(e.RowColumnIndex.RowIndex), GetColumn(e.RowColumnIndex.ColumnIndex));
+            Parent.DoubleClickCell(GetRowFromIndex(e.RowColumnIndex.RowIndex), GetColumn(e.RowColumnIndex.ColumnIndex));
         });
     }
 
@@ -319,7 +335,17 @@ public class DynamicGridTreeUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
 
     private CoreRow? GetRow(CoreTreeNode? node)
     {
-        return node is not null ? _rowMap?.GetValueOrDefault(node.ID) : null;
+        return MapRow(node?.Row);
+    }
+
+    private CoreRow? MapRow(CoreRow? row)
+    {
+        if (row is null) return null;
+
+        var index = row.Index;
+        if (index < 0 || index >= Parent.Data.Rows.Count) return null;
+
+        return Parent.Data.Rows[row.Index];
     }
 
     private void ColumnsMenu_ContextMenuOpening(object sender, RoutedEventArgs e)
@@ -333,6 +359,29 @@ public class DynamicGridTreeUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
     public bool OptionsChanged()
     {
         ColumnsMenu.Visibility = Parent.HasOption(DynamicGridOption.SelectColumns) ? Visibility.Visible : Visibility.Hidden;
+
+        _tree.AllowFiltering = Parent.HasOption(DynamicGridOption.FilterRows);
+
+        if (Parent.HasOption(DynamicGridOption.DragSource))
+        {
+            if (!_tree.AllowDraggingRows)
+            {
+                _tree.AllowDraggingRows = true;
+                _tree.RowDragDropController.DragStart += RowDragDropController_DragStart;
+            }
+        }
+        else
+        {
+            if (_tree.AllowDraggingRows)
+            {
+                _tree.AllowDraggingRows = false;
+                _tree.RowDragDropController.DragStart -= RowDragDropController_DragStart;
+            }
+        }
+        
+        _tree.AllowDrop = Parent.HasOption(DynamicGridOption.DragTarget);
+        _tree.SelectionMode = Parent.HasOption(DynamicGridOption.MultiSelect) ? GridSelectionMode.Extended : GridSelectionMode.Single;
+
         return false;
     }
 
@@ -489,7 +538,7 @@ public class DynamicGridTreeUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
             var column = ActionColumns[i];
             if (column.Position == position)
             {
-                var sColName = string.Format("ActionColumn{0}", i);
+                var sColName = $"[_ActionColumn{i}]";
 
                 if (column is DynamicImageColumn imgcol)
                 {
@@ -502,7 +551,7 @@ public class DynamicGridTreeUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
                             Width = _tree.RowHeight - 8,
                             Height = _tree.RowHeight - 8,
                         };
-                        image.SetBinding(Image.SourceProperty, new Binding(sColName) { Converter = new BytesToBitmapImageConverter() });
+                        image.SetBinding(Image.SourceProperty, new Binding(sColName));
                         return image;
                     } };
 
@@ -536,7 +585,7 @@ public class DynamicGridTreeUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
                         var image = imgcol.Image?.Invoke(null);
                         if (image != null)
                         {
-                            var template = new ControlTemplate(typeof(TreeGridHeaderCell));
+                            var template = new DataTemplate(typeof(TreeGridHeaderCell));
                             var border = new FrameworkElementFactory(typeof(Border));
                             border.SetValue(Border.BackgroundProperty, new SolidColorBrush(Colors.Gainsboro));
                             border.SetValue(Border.PaddingProperty, new Thickness(4));
@@ -545,7 +594,8 @@ public class DynamicGridTreeUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
                             img.SetValue(Image.SourceProperty, image);
                             border.AppendChild(img);
                             template.VisualTree = border;
-                            headstyle.Setters.Add(new Setter(Control.TemplateProperty, template));
+                            headstyle.Setters.Add(new Setter(TreeGridHeaderCell.PaddingProperty, new Thickness(0)));
+                            headstyle.Setters.Add(new Setter(TreeGridHeaderCell.ContentTemplateProperty, template));
                         }
                     }
 
@@ -708,19 +758,13 @@ public class DynamicGridTreeUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
 
         ActionColumns = actionColumns.ToList();
         
-        _tree.Columns.Add(new TreeGridTextColumn()
-            {
-                MappingName = "Description"
-            }
-        );
-        
-        _tree.Columns.Add(new TreeGridTextColumn()
-            {
-                MappingName = "Number",
-                Width = _shownumbers ? 50 : 0,
-                TextAlignment = TextAlignment.Right
-            }
-        );
+        //_tree.Columns.Add(new TreeGridTextColumn()
+        //    {
+        //        MappingName = "Number",
+        //        Width = _shownumbers ? 50 : 0,
+        //        TextAlignment = TextAlignment.Right
+        //    }
+        //);
 
         LoadActionColumns(DynamicActionColumnPosition.Start);
         LoadDataColumns(columns);
@@ -764,6 +808,8 @@ public class DynamicGridTreeUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
 
     public CoreTreeNodes Nodes { get; set; }
 
+    private CoreTable? _innerTable;
+
     public void BeforeRefresh()
     {
         _tree.SelectionForeground = DynamicGridUtils.SelectionForeground;
@@ -773,12 +819,37 @@ public class DynamicGridTreeUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
     public void RefreshData(CoreTable data)
     {
         var nodes = new CoreTreeNodes();
+
+        _innerTable = new CoreTable();
+        _innerTable.LoadColumns(data.Columns);
+
+        for (var i = 0; i < ActionColumns.Count; i++)
+            _innerTable.Columns.Add(
+                new CoreColumn
+                {
+                    ColumnName = $"_ActionColumn{i}",
+                    DataType = ActionColumns[i] is DynamicImageColumn
+                        ? typeof(BitmapImage)
+                        : typeof(String)
+                });
+
         foreach (var row in data.Rows)
         {
+            var newRow = _innerTable.NewRow();
+            newRow.LoadValues(row.Values);
+
+            for (var i = 0; i < ActionColumns.Count; i++)
+            {
+                var ac = ActionColumns[i];
+                newRow[$"_ActionColumn{i}"] = ac.Data(row);
+            }
+
+            _innerTable.Rows.Add(newRow);
+
             var _id = row.Get<Guid>(IDColumn.Property);
             var _parent = row.Get<Guid>(ParentColumn.Property);
             var _description = row.Get<string>(DescriptionColumn.Property);
-            nodes.Add(_id, _parent, row).Description = _description;
+            nodes.Add(_id, _parent, newRow).Description = _description;
         }
         Nodes = nodes;
         _tree.ItemsSource = nodes.Nodes;
@@ -838,19 +909,18 @@ public class DynamicGridTreeUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
 
     public CoreRow[] GetVisibleRows()
     {
-        return _tree.View.Nodes.Select(x => (x.Item as CoreTreeNode)?.Row).NotNull().ToArray();
+        return _tree.View.Nodes.Select(x => MapRow((x.Item as CoreTreeNode)?.Row)).NotNull().ToArray();
     }
 
     public void InvalidateRow(CoreRow row)
     {
-        var rowdata = new List<object?>(row.Values);
-        foreach (var ac in ActionColumns)
-            rowdata.Add(ac.Data(row));
+        if (_innerTable is null || row.Index < 0 || row.Index >= _innerTable.Rows.Count) return;
 
-        var coreTreeNode = Nodes.Find(row);
+        var _innerRow = _innerTable.Rows[row.Index];
+        var coreTreeNode = Nodes.Find(_innerRow);
         if(coreTreeNode is not null)
         {
-            coreTreeNode.Row = row;;
+            coreTreeNode.InvalidateData();
         }
     }
 
@@ -869,4 +939,24 @@ public class DynamicGridTreeUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
     {
         throw new NotImplementedException();
     }
+
+    #region Drag + Drop
+
+    private void _tree_DragOver(object sender, DragEventArgs e)
+    {
+        Parent.DragOver(sender, e);
+    }
+
+    private void _tree_Drop(object sender, DragEventArgs e)
+    {
+        Parent.Drop(sender, e);
+    }
+
+    private void RowDragDropController_DragStart(object? sender, TreeGridRowDragStartEventArgs e)
+    {
+        var rows = e.DraggingNodes.Select(node => MapRow((node.Item as CoreTreeNode)?.Row)).NotNull().ToArray();
+        Parent.DragStart(sender, rows);
+    }
+
+    #endregion
 }