Browse Source

Drag-drop for row movement

Kenric Nugteren 7 months ago
parent
commit
60b5851d1b

+ 45 - 18
inabox.wpf/DynamicGrid/DynamicGrid.cs

@@ -388,6 +388,11 @@ public abstract class DynamicGrid<T> : DynamicGrid, IDynamicGridUIComponentParen
         };
     }
 
+    bool IDynamicGridUIComponentParent<T>.CanFilter()
+    {
+        return !ShowSequenceButtons || !Options.EditRows;
+    }
+
     bool IDynamicGridUIComponentParent<T>.CanSort()
     {
         return !ShowSequenceButtons || !Options.EditRows;
@@ -768,6 +773,7 @@ public abstract class DynamicGrid<T> : DynamicGrid, IDynamicGridUIComponentParen
     public void Reconfigure(DynamicGridOptions options)
     {
         options.BeginUpdate().Clear();
+        options.DragRows = IsSequenced;
         DoReconfigure(options);
         OnReconfigureEvent(options);
         options.EndUpdate();
@@ -941,21 +947,6 @@ public abstract class DynamicGrid<T> : DynamicGrid, IDynamicGridUIComponentParen
         return ExtractColumns(cols);
     }
 
-    private bool SwapRows(int row1, int row2)
-    {
-
-        CoreRow[] rows = Data.Rows.Where(x => x.Index.Equals(row1) || x.Index.Equals(row2)).ToArray();
-        var items = LoadItems(rows);
-        var first = (items.First() as ISequenceable)!;
-        var last = (items.Last() as ISequenceable)!;
-        var iBuf1 = first.Sequence;
-        var iBuf2 = last.Sequence;
-        first.Sequence = iBuf2;
-        last.Sequence = iBuf1;
-        SaveItems(items);
-        return true;
-    }
-
     protected virtual void SaveColumns(DynamicGridColumns columns)
     {
     }
@@ -2128,6 +2119,43 @@ public abstract class DynamicGrid<T> : DynamicGrid, IDynamicGridUIComponentParen
         }
     }
 
+    private bool SwapRows(int row1, int row2)
+    {
+        CoreRow[] rows = Data.Rows.Where(x => x.Index.Equals(row1) || x.Index.Equals(row2)).ToArray();
+        var items = LoadItems(rows);
+        var first = (items.First() as ISequenceable)!;
+        var last = (items.Last() as ISequenceable)!;
+        var iBuf1 = first.Sequence;
+        var iBuf2 = last.Sequence;
+        first.Sequence = iBuf2;
+        last.Sequence = iBuf1;
+        SaveItems(items);
+        return true;
+    }
+
+    void IDynamicGridUIComponentParent<T>.MoveRows(InABox.Core.CoreRow[] rows, int index) => MoveRows(rows, index);
+
+    protected virtual void MoveRows(CoreRow[] rows, int index)
+    {
+        var sequence = index < Data.Rows.Count
+            ? Data.Rows[index].Get<ISequenceable, long>(x => x.Sequence)
+            : Data.Rows[^1].Get<ISequenceable, long>(x => x.Sequence) + 1;
+
+        var postRows = Data.Rows.Where(r => !rows.Contains(r) && r.Get<ISequenceable, long>(x => x.Sequence) >= sequence);
+
+        var updates = rows.Concat(postRows).ToObjects<T>().ToArray();
+        foreach (var update in updates)
+        {
+            ((ISequenceable)update).Sequence = sequence;
+            sequence++;
+        }
+
+        if (updates.Length != 0)
+        {
+            SaveItems(updates);
+            Refresh(false, true);
+        }
+    }
 
     #region ClipBuffer
 
@@ -2149,7 +2177,6 @@ public abstract class DynamicGrid<T> : DynamicGrid, IDynamicGridUIComponentParen
         InvalidateGrid();
     }
 
-
     private void CopyToClipBuffer()
     {
         SetClipBuffer(ClipAction.Copy, SelectedRows);
@@ -2184,9 +2211,9 @@ public abstract class DynamicGrid<T> : DynamicGrid, IDynamicGridUIComponentParen
                 }
             }
 
-            if (updates.Any())
+            if (updates.Count != 0)
             {
-                SaveItems(updates.ToArray());
+                SaveItems(updates);
                 Refresh(false, true);
             }
         }

+ 24 - 1
inabox.wpf/DynamicGrid/DynamicGridColumn/DynamicColumnGrid.cs

@@ -6,7 +6,7 @@ using InABox.Core;
 
 namespace InABox.DynamicGrid;
 
-internal class DynamicColumnGrid : DynamicGrid<DynamicGridColumn>
+public class DynamicColumnGrid : DynamicGrid<DynamicGridColumn>
 {
     public DynamicColumnGrid()
     {
@@ -32,6 +32,8 @@ internal class DynamicColumnGrid : DynamicGrid<DynamicGridColumn>
         options.AddRows = true;
         options.EditRows = true;
         options.DeleteRows = true;
+
+        options.DragRows = true;
     }
 
     public Type Type { get; set; }
@@ -48,6 +50,27 @@ internal class DynamicColumnGrid : DynamicGrid<DynamicGridColumn>
         return true;
     }
 
+    protected override void MoveRows(CoreRow[] rows, int index)
+    {
+        var targetCol = index < Columns.Count ? Columns[index] : null;
+ 
+        var cols = LoadItems(rows);
+        foreach(var col in cols)
+        {
+            Columns.Remove(col);
+        }
+        if(targetCol is not null)
+        {
+            var idx = Columns.IndexOf(targetCol);
+            Columns.InsertRange(idx, cols);
+        }
+        else
+        {
+            Columns.AddRange(cols);
+        }
+        Refresh(false, true);
+    }
+
     protected override void DoAdd(bool openEditorOnDirectEdit = false)
     {
         if(DynamicGridColumnNameSelectorGrid.SelectColumnName(ProcessColumns().Select(x => x.ColumnName).ToArray(), out var column))

+ 6 - 2
inabox.wpf/DynamicGrid/DynamicGridColumn/DynamicGridColumnNameSelectorWindow.cs

@@ -207,7 +207,9 @@ public class DynamicGridColumnNameSelectorGrid : DynamicItemsListGrid<DynamicGri
 
     public static bool SelectColumnName(string[] columnNames, out string value)
     {
-        var grid = new DynamicGridColumnNameSelectorGrid(columnNames);
+        var grid = new DynamicGridColumnNameSelectorGrid(columnNames)
+        {
+        };
         grid.Refresh(true, true);
 
         var lbl = new Label
@@ -242,7 +244,9 @@ public class DynamicGridColumnNameSelectorGrid : DynamicItemsListGrid<DynamicGri
 
         var window = new DynamicContentDialog(control)
         {
-            Title = "Select Column"
+            Title = "Select Column",
+            Width = 400,
+            Height = 600
         };
         window.Bind(DynamicContentDialog.CanSaveProperty, grid, x => x.CanSave);
 

+ 19 - 19
inabox.wpf/DynamicGrid/DynamicGridCommon.cs

@@ -22,25 +22,6 @@ public abstract class DynamicColumnBase : BaseObject, IDynamicColumnBase
     
 }
 
-public enum DynamicGridOption
-{
-    AddRows,
-    EditRows,
-    DeleteRows,
-    FilterRows,
-    SelectColumns,
-    ExportData,
-    ImportData,
-    MultiSelect,
-    DragSource,
-    DragTarget,
-    DirectEdit,
-    ShowHelp,
-    Print,
-    RecordCount,
-    HideDatabaseFilters,
-    HideDirectEditButton
-}
 public class DynamicGridOptions
 {
     public event Action? OnChanged;
@@ -245,6 +226,25 @@ public class DynamicGridOptions
 			}
 		}
 	}
+    private bool _dragRows;
+	/// <summary>
+	/// Allow dragging rows within this grid.
+	/// </summary>
+	/// <remarks>
+	/// <see cref="DragSource"/> and <see cref="DragTarget"/> deal with external dragging, whereas this deals with internal dragging.
+	/// </remarks>
+    public bool DragRows
+	{
+		get => _dragRows && EditRows;
+		set
+		{
+			if(_dragRows != value)
+			{
+				_dragRows = value;
+				Changed();
+			}
+		}
+	}
     private bool _directEdit;
     public bool DirectEdit
 	{

+ 87 - 13
inabox.wpf/DynamicGrid/UIComponent/DynamicGridGridUIComponent.cs

@@ -169,14 +169,16 @@ public class DynamicGridGridUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
         DataGrid.DragOver += DataGrid_DragOver;
         DataGrid.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;
+            // 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;
+            return null;
         });
+        DataGrid.RowDropIndicatorMode = DropIndicatorMode.Line;
         
         DataGrid.CurrentCellBorderThickness = new Thickness(0);
         DataGrid.AllowFiltering = false;
@@ -550,15 +552,16 @@ public class DynamicGridGridUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
             DataGrid.AllowEditing = allowEditing;
             reloadColumns = true;
         }
-        DataGrid.AllowFiltering = Parent.Options.FilterRows;
-        DataGrid.FilterRowPosition = Parent.Options.FilterRows ? FilterRowPosition.FixedTop : FilterRowPosition.None;
+        DataGrid.AllowFiltering = Parent.Options.FilterRows && Parent.CanFilter();
+        DataGrid.FilterRowPosition = Parent.Options.FilterRows && Parent.CanFilter() ? FilterRowPosition.FixedTop : FilterRowPosition.None;
 
-        if (Parent.Options.DragSource)
+        if (Parent.Options.DragSource || Parent.Options.DragRows)
         {
             if (!DataGrid.AllowDraggingRows)
             {
                 DataGrid.AllowDraggingRows = true;
                 DataGrid.RowDragDropController.DragStart += RowDragDropController_DragStart;
+                DataGrid.RowDragDropController.DragOver += RowDragDropController_DragOver;
             }
         }
         else
@@ -567,16 +570,34 @@ public class DynamicGridGridUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
             {
                 DataGrid.AllowDraggingRows = false;
                 DataGrid.RowDragDropController.DragStart -= RowDragDropController_DragStart;
+                DataGrid.RowDragDropController.DragOver -= RowDragDropController_DragOver;
+            }
+        }
+
+        if (Parent.Options.DragTarget || Parent.Options.DragRows)
+        {
+            if (!DataGrid.AllowDrop)
+            {
+                DataGrid.AllowDrop = true;
+                DataGrid.RowDragDropController.Drop += RowDragDropController_Drop;
+                DataGrid.RowDragDropController.Dropped += RowDragDropController_Dropped;
+            }
+        }
+        else
+        {
+            if (DataGrid.AllowDrop)
+            {
+                DataGrid.AllowDrop = false;
+                DataGrid.RowDragDropController.Drop -= RowDragDropController_Drop;
+                DataGrid.RowDragDropController.Dropped -= RowDragDropController_Dropped;
             }
         }
-        
-        DataGrid.AllowDrop = Parent.Options.DragTarget;
         
         DataGrid.SelectionMode = Parent.Options.MultiSelect ? GridSelectionMode.Extended : GridSelectionMode.Single;
 
         return reloadColumns && DataGrid.Columns.Count > 0;
     }
-    
+
     private void DataGrid_FilterChanging(object? sender, GridFilterEventArgs e)
     {
         
@@ -1828,11 +1849,19 @@ public class DynamicGridGridUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
 
     private void DataGrid_DragOver(object sender, DragEventArgs e)
     {
+        if (!Parent.Options.DragTarget)
+        {
+            return;
+        }
         Parent.DragOver(sender, e);
     }
 
     private void DataGrid_Drop(object sender, DragEventArgs e)
     {
+        if (!Parent.Options.DragTarget)
+        {
+            return;
+        }
         Parent.Drop(sender, e);
     }
 
@@ -1846,5 +1875,50 @@ public class DynamicGridGridUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
         Parent.DragStart(sender, rows);
     }
 
+    private void RowDragDropController_Drop(object? sender, GridRowDropEventArgs e)
+    {
+        if (!Parent.Options.DragRows)
+        {
+            e.Handled = true;
+        }
+        e.Handled = true;
+    }
+
+    private void RowDragDropController_Dropped(object? sender, GridRowDroppedEventArgs e)
+    {
+        if (!Parent.Options.DragRows)
+        {
+        }
+
+        if(e.DropPosition != DropPosition.None)
+        {
+            var records = (e.Data.GetData("Records") as ObservableCollection<object>)!;
+            var targetIdx = (int)e.TargetRecord;
+
+            var rows = records.Select(x =>
+            {
+                if (x is DataRowView dataRow)
+                {
+                    var row = dataRow.Row.Table.Rows.IndexOf(dataRow.Row);
+                    return Parent.Data.Rows[row];
+                }
+                else
+                {
+                    return null;
+                }
+            }).NotNull().OrderBy(x => x.Index).ToArray();
+
+            Parent.MoveRows(rows, e.DropPosition == DropPosition.DropBelow ? targetIdx + 1 : targetIdx);
+        }
+    }
+
+    private void RowDragDropController_DragOver(object? sender, GridRowDragOverEventArgs e)
+    {
+        if (!Parent.Options.DragRows)
+        {
+            e.Handled = true;
+        }
+    }
+
     #endregion
 }

+ 10 - 0
inabox.wpf/DynamicGrid/UIComponent/IDynamicGridUIComponent.cs

@@ -16,6 +16,7 @@ public interface IDynamicGridUIComponentParent<T> : IDynamicGrid<T>
 {
     bool IsRefreshing { get; }
 
+    bool CanFilter();
     bool CanSort();
 
     DynamicGridRowStyleSelector<T> RowStyleSelector { get; }
@@ -43,6 +44,15 @@ public interface IDynamicGridUIComponentParent<T> : IDynamicGrid<T>
     void DragOver(object sender, DragEventArgs e);
     void Drop(object sender, DragEventArgs e);
     void DragStart(object? sender, CoreRow[] rows);
+
+    /// <summary>
+    /// Move the given rows from where they are, inserting them at <paramref name="index"/>. (i.e., before the row at the given index).
+    /// To insert at the end, set <paramref name="index"/> to the number of rows.
+    /// </summary>
+    /// <remarks>
+    /// Only applicable if <typeparamref name="T"/> is <see cref="ISequenceable"/>.
+    /// </remarks>
+    void MoveRows(CoreRow[] rows, int index);
     
     void UIFilterChanged(object sender);
     IEnumerable<string>? GetColumnFilterItems(DynamicColumnBase column);