Procházet zdrojové kódy

- Allowed for adding elements to a FormDesignGrid that need a Func<> to create the element.
- Removed redundant utility function

Kenric Nugteren před 6 měsíci
rodič
revize
776e565769

+ 8 - 0
inabox.wpf/Dashboard/DynamicDashboardDataComponent.cs

@@ -73,6 +73,10 @@ public class DynamicDashboardDataComponent
         return query != null;
     }
 
+    /// <summary>
+    /// Run the query to get the data according to the definitions of <see cref="Queries"/>.
+    /// </summary>
+    /// <param name="maxRecords">Set to a non-<see langword="null"/> value to limit the number of records returned. Used for preview mode.</param>
     public DynamicDashboardData RunQuery(int? maxRecords = null)
     {
         var range = maxRecords.HasValue ? CoreRange.Database(maxRecords.Value) : null;
@@ -81,6 +85,10 @@ public class DynamicDashboardDataComponent
         return new DynamicDashboardData(results.Results);
     }
 
+    /// <summary>
+    /// Run the query asynchronously to get the data according to the definitions of <see cref="Queries"/>.
+    /// </summary>
+    /// <param name="maxRecords">Set to a non-<see langword="null"/> value to limit the number of records returned. Used for preview mode.</param>
     public async Task<DynamicDashboardData> RunQueryAsync(int? maxRecords = null)
     {
         var range = maxRecords.HasValue ? CoreRange.Database(maxRecords.Value) : null;

+ 71 - 51
inabox.wpf/DigitalForms/Designer/DynamicFormDesignGrid.cs

@@ -198,6 +198,9 @@ namespace InABox.DynamicGrid
         public event CreateVariableHandler? OnCreateVariable;
         public event EditVariableHandler? OnEditVariable;
 
+        public delegate void CustomiseElementContextMenuHandler(ContextMenu menu, DFLayoutElement element);
+        public event CustomiseElementContextMenuHandler? CustomiseElementContextMenu;
+
         public IList<DigitalFormVariable> Variables
         {
             get => _variables;
@@ -276,18 +279,20 @@ namespace InABox.DynamicGrid
             public string Caption { get; set; }
             public Type ElementType { get; set; }
             public string Category { get; set; }
-            public FrameworkElement? Element { get; set; }
             public bool AllowDuplicate { get; set; }
+            public object? Tag { get; set; }
+            public Func<object?, DFLayoutElement>? CreateElement { get; set; }
 
             public bool Visible { get; set; }
 
-            public DynamicFormElement(string caption, Type elementType, string category, FrameworkElement? element, bool allowDuplicate, bool visible)
+            public DynamicFormElement(string caption, Type elementType, string category, bool allowDuplicate, bool visible, object? tag, Func<object?, DFLayoutElement>? createElement)
             {
                 Caption = caption;
                 ElementType = elementType;
                 Category = category;
-                Element = element;
                 AllowDuplicate = allowDuplicate;
+                Tag = tag;
+                CreateElement = createElement;
                 Visible = visible;
             }
         }
@@ -319,10 +324,20 @@ namespace InABox.DynamicGrid
         {
             AddElement(typeof(TElement), caption, category, allowduplicate, visible: visible);
         }
+        public void AddElement<TElement, TTag>(string caption, string category, TTag tag, Func<TTag, TElement> createElement, bool allowduplicate = false, bool visible = true)
+            where TElement : DFLayoutElement
+        {
+            AddElement(typeof(TElement), caption, category, tag, createElement, allowduplicate, visible: visible);
+        }
 
         public void AddElement(Type TElement, string caption, string category, bool allowduplicate = false, bool visible = true)
         {
-            _elements.Add(new DynamicFormElement(caption, TElement, category, null, allowduplicate, visible));
+            _elements.Add(new DynamicFormElement(caption, TElement, category, allowduplicate, visible, null, null));
+        }
+
+        public void AddElement<TTag>(Type TElement, string caption, string category, TTag tag, Func<TTag, DFLayoutElement> createElement, bool allowduplicate = false, bool visible = true)
+        {
+            _elements.Add(new DynamicFormElement(caption, TElement, category, allowduplicate, visible, tag, x => createElement((TTag)x)));
         }
 
         public void AddElementAction<TTag>(string caption, Bitmap? image, string category, TTag tag, Func<TTag, DFLayoutElement?> onClick)
@@ -401,14 +416,6 @@ namespace InABox.DynamicGrid
             return string.Format("{0}px", length.Value);
         }
 
-        private static MenuItem CreateMenuItem<TTag>(string caption, TTag tag, Action<TTag>? click)
-        {
-            var result = new MenuItem { Header = caption, Tag = tag };
-            if (click != null)
-                result.Click += (o, e) => click((TTag)(o as MenuItem)!.Tag);
-            return result;
-        }
-
         private static void AddClick<TTag>(ButtonBase button, TTag tag, Action<TTag> click)
         {
             button.Tag = tag;
@@ -1318,16 +1325,16 @@ namespace InABox.DynamicGrid
 
         private void PopulateRowMenu(ContextMenu menu, int row)
         {
-            menu.Items.Add(CreateMenuItem("Add Row Before", row, AddRowBeforeClick));
-            menu.Items.Add(CreateMenuItem("Add Row After", row, AddRowAfterClick));
-            menu.Items.Add(new Separator());
-            menu.Items.Add(CreateMenuItem("Split Row", row, SplitRowClick));
-            var propertiesSeparator = new Separator();
-            var propertiesMenu = CreateMenuItem("Row Properties", row, RowPropertiesClick);
-            menu.Items.Add(propertiesSeparator);
-            menu.Items.Add(propertiesMenu);
-            menu.Items.Add(new Separator());
-            menu.Items.Add(CreateMenuItem("Delete Row", new Range(row, row), DeleteRows));
+            menu.AddItem("Add Row Before", null, row, AddRowBeforeClick);
+            menu.AddItem("Add Row After", null, row, AddRowAfterClick);
+            menu.AddSeparator();
+            menu.AddItem("Split Row", null, row, SplitRowClick);
+
+            var propertiesSeparator = menu.AddSeparator();
+            var propertiesMenu = menu.AddItem("Row Properties", null, row, RowPropertiesClick);
+
+            menu.AddSeparator();
+            menu.AddItem("Delete Row", null, new Range(row, row), DeleteRows);
             menu.Opened += (o, e) =>
             {
                 propertiesSeparator.Visibility = form.RowHeights.Count > 1 ? Visibility.Visible : Visibility.Collapsed;
@@ -1451,16 +1458,14 @@ namespace InABox.DynamicGrid
 
         private void PopulateColumnMenu(ContextMenu menu, int column)
         {
-            menu.Items.Add(CreateMenuItem("Add Column Before", column, AddColumnBeforeClick));
-            menu.Items.Add(CreateMenuItem("Add Column After", column, AddColumnAfterClick));
-            menu.Items.Add(new Separator());
-            menu.Items.Add(CreateMenuItem("Split Column", column, SplitColumnClick));
-            var propertiesSeparator = new Separator();
-            var propertiesMenu = CreateMenuItem("Column Properties", column, ColumnPropertiesClick);
-            menu.Items.Add(propertiesSeparator);
-            menu.Items.Add(propertiesMenu);
-            menu.Items.Add(new Separator());
-            menu.Items.Add(CreateMenuItem("Delete Column", new Range(column, column), DeleteColumns));
+            menu.AddItem("Add Column Before", null, column, AddColumnBeforeClick);
+            menu.AddItem("Add Column After", null, column, AddColumnAfterClick);
+            menu.AddSeparator();
+            menu.AddItem("Split Column", null, column, SplitColumnClick);
+            var propertiesSeparator = menu.AddSeparator();
+            var propertiesMenu = menu.AddItem("Column Properties", null, column, ColumnPropertiesClick);
+            menu.AddSeparator();
+            menu.AddItem("Delete Column", null, new Range(column, column), DeleteColumns);
             menu.Opened += (o, e) =>
             {
                 propertiesSeparator.Visibility = form.ColumnWidths.Count > 1 ? Visibility.Visible : Visibility.Collapsed;
@@ -1480,10 +1485,22 @@ namespace InABox.DynamicGrid
 
         #region Add Element
 
-        private void AddNewElement<TElement>(CellRange range)
+        private void AddNewElement<TElement>(DynamicFormElement elementDef, CellRange range)
             where TElement : DFLayoutElement, new()
         {
-            var element = new TElement();
+            TElement? element;
+            if (elementDef.CreateElement is not null)
+            {
+                element = elementDef.CreateElement(elementDef.Tag) as TElement;
+            }
+            else
+            {
+                element = new();
+            }
+            if(element is null)
+            {
+                return;
+            }
             SetControlRange(element, range);
 
             var result = new FormControlGrid<TElement>().EditItems(new[] { element });
@@ -1494,12 +1511,12 @@ namespace InABox.DynamicGrid
             }
         }
 
-        private void AddElementClick(Tuple<Type, CellRange> tuple)
+        private void AddElementClick(Tuple<DynamicFormElement, CellRange> tuple)
         {
             var method = typeof(DynamicFormDesignGrid)
                 .GetMethod(nameof(AddNewElement), BindingFlags.NonPublic | BindingFlags.Instance)!
-                .MakeGenericMethod(tuple.Item1);
-            method.Invoke(this, new object[] { tuple.Item2 });
+                .MakeGenericMethod(tuple.Item1.ElementType);
+            method.Invoke(this, new object[] { tuple.Item1, tuple.Item2 });
         }
 
         private void ElementActionClick(Tuple<DynamicFormElementAction, CellRange> tuple)
@@ -1619,7 +1636,7 @@ namespace InABox.DynamicGrid
                 menu.Items.Remove(fields);
             }
 
-            var elements = CreateMenuItem("Add Object", cellRange, null);
+            var elements = menu.AddItem("Add Object", null, cellRange, null);
 
             var available = _elements.Where(x => x.Visible && (x.AllowDuplicate || !form.Elements.Any(v => (v as DFLayoutElement)?.GetType() == x.ElementType)))
                 .ToArray();
@@ -1630,8 +1647,7 @@ namespace InABox.DynamicGrid
                 var parentMenu = elements;
                 if (!string.IsNullOrWhiteSpace(cat))
                 {
-                    parentMenu = new MenuItem { Header = cat };
-                    elements.Items.Add(parentMenu);
+                    parentMenu = elements.AddItem(cat, null, null);
                 }
 
                 foreach(var action in _elementActions.Where(x => x.Category == cat))
@@ -1642,12 +1658,12 @@ namespace InABox.DynamicGrid
                 parentMenu.AddSeparatorIfNeeded();
 
                 foreach (var element in available.Where(x => string.Equals(x.Category, cat)))
-                    parentMenu.AddItem(element.Caption, null, new Tuple<Type, CellRange>(element.ElementType, cellRange), AddElementClick);
+                    parentMenu.AddItem(element.Caption, null, new Tuple<DynamicFormElement, CellRange>(element, cellRange), AddElementClick);
                 parentMenu.RemoveUnnecessarySeparators();
             }
 
-            if (elements.Items.Count > 0)
-                menu.Items.Add(elements);
+            if (elements.Items.Count == 0)
+                menu.Items.Remove(elements);
         }
 
         private ContextMenu CreateEmptyCellMenu(Border border, int row, int column)
@@ -1759,22 +1775,26 @@ namespace InABox.DynamicGrid
                 if(menu.Items.Count > 0) return;
             }
 
-            menu.Items.Add(CreateMenuItem("Edit Properties", control, ElementPropertiesClick));
+            menu.AddItem("Edit Properties", null, control, ElementPropertiesClick);
             if (OnEditVariable is not null && control is DFLayoutField field)
             {
-                menu.Items.Add(CreateMenuItem("Edit Variable", field, EditVariableClick));
+                menu.AddItem("Edit Variable", null, field, EditVariableClick);
+            }
+            else if (control is DFLayoutLabel label)
+            {
+                menu.AddItem("Convert to Header", null, label, ConvertToHeaderClick);
             }
-            if (control is DFLayoutLabel label)
+            else if (control is DFLayoutHeader header)
             {
-                menu.Items.Add(CreateMenuItem("Convert to Header", label, ConvertToHeaderClick));
+                menu.AddItem("Convert to Label", null, header, ConvertToLabelClick);
             }
-            if (control is DFLayoutHeader header)
+            else if(control is DFLayoutElement element)
             {
-                menu.Items.Add(CreateMenuItem("Convert to Label", header, ConvertToLabelClick));
+                CustomiseElementContextMenu?.Invoke(menu, element);
             }
-            menu.Items.Add(new Separator());
+            menu.AddSeparatorIfNeeded();
             menu.AddItem("Resize Item", null, control, ResizeItem);
-            menu.Items.Add(CreateMenuItem("Delete Item", control, DeleteElementClick));
+            menu.AddItem("Delete Item", null, control, DeleteElementClick);
         }
 
         private ContextMenu CreateElementContextMenu(FrameworkElement element, DFLayoutControl control)