瀏覽代碼

DynamicEditorControls can now be picked based on value type. Added new list editor for IList instead of serialised stirngs.

Kenric Nugteren 4 月之前
父節點
當前提交
3b04fbb761

+ 13 - 0
InABox.Core/Objects/BaseObject.cs

@@ -549,6 +549,19 @@ namespace InABox.Core
             obj._disabledInterceptor = false;
             return newObj;
         }
+        public static BaseObject Clone(BaseObject obj)
+        {
+            var newObj = (Activator.CreateInstance(obj.GetType()) as BaseObject)!;
+            obj._disabledInterceptor = true;
+            foreach(var property in DatabaseSchema.Properties(obj.GetType()))
+            {
+                if (property.Parent != null && property.Parent.NullSafeGetter()(obj) is null) continue;
+
+                property.Setter()(newObj, property.Getter()(obj));
+            }
+            obj._disabledInterceptor = false;
+            return newObj;
+        }
 
         public static bool HasChanged(object? before, object? after)
         {

+ 4 - 1
InABox.Core/Objects/Editors/EmbeddedListEditor.cs

@@ -13,6 +13,8 @@ namespace InABox.Core
         
         public bool DirectEdit { get; set; }
 
+        public bool AddRows { get; set; }
+
         public event EmbeddedListEditorCreateButtons OnCreateButtons;
 
         public void CreateButtons(object sender) => OnCreateButtons?.Invoke(sender);
@@ -24,9 +26,10 @@ namespace InABox.Core
             DataType = dataType;
             Label = "Edit";
             DirectEdit = false;
+            AddRows = true;
         }
 
-        protected override BaseEditor DoClone() => new EmbeddedListEditor(DataType) { Label = this.Label, DirectEdit = this.DirectEdit };
+        protected override BaseEditor DoClone() => new EmbeddedListEditor(DataType) { Label = this.Label, DirectEdit = this.DirectEdit, AddRows = this.AddRows };
         
     }
 }

+ 2 - 0
InABox.Core/Objects/Editors/Utils/EditorTypeUtils.cs

@@ -20,6 +20,8 @@ namespace InABox.Core
                 editor = new CheckBoxEditor();
             else if (type == typeof(DateTime))
                 editor = new DateTimeEditor();
+            else if (type == typeof(TimeSpan))
+                editor = new DurationEditor();
             else if (type == typeof(string))
                 editor = new TextBoxEditor();
             else if (type.IsFloatingPoint())

+ 8 - 6
inabox.wpf/DynamicGrid/DynamicEditorForm/DynamicEditorGrid.xaml.cs

@@ -33,6 +33,8 @@ public partial class DynamicEditorGrid : UserControl, IDynamicEditorHost
     // Column Definitions as defined by calling model
     private DynamicGridColumns _columns = new();
 
+    public IDynamicEditorForm Form { get; set; }
+
     private Type? LayoutType;
     private DynamicEditorGridLayout? Layout;
 
@@ -250,9 +252,9 @@ public partial class DynamicEditorGrid : UserControl, IDynamicEditorHost
             InitialiseContent();
         }
 
-        public void AddEditor(string columnName, BaseEditor editor)
+        public void AddEditor(string columnName, BaseEditor editor, Type valueType)
         {
-            BaseDynamicEditorControl? element = DynamicEditorControlFactory.CreateControl(editor, EditorGrid);
+            BaseDynamicEditorControl? element = DynamicEditorControlFactory.CreateControl(editor, valueType, EditorGrid);
             
             if (element != null)
             {
@@ -613,13 +615,13 @@ public partial class DynamicEditorGrid : UserControl, IDynamicEditorHost
             InitialiseLayout();
         }
 
-        var editors = new List<(IProperty?, string, BaseEditor)>();
+        var editors = new List<(IProperty, string, BaseEditor)>();
         foreach (var column in _columns.OrderBy(x => GetSequence(x)))
         {
-            var iProp = DatabaseSchema.Property(UnderlyingType, column.ColumnName);
+            var iProp = DatabaseSchema.PropertyStrict(UnderlyingType, column.ColumnName);
             var editor = OnGetEditor?.Invoke(column);
 
-            if (editor != null && iProp?.ShouldShowEditor() != true)
+            if (editor != null && iProp.ShouldShowEditor() != true)
             {
                 editor.Visible = Visible.Hidden;
                 editor.Editable = Editable.Hidden;
@@ -677,7 +679,7 @@ public partial class DynamicEditorGrid : UserControl, IDynamicEditorHost
             var editPage = GetEditPage(page);
             if (!editPage.TryFindEditor(name, out var editorControl))
             {
-                editPage.AddEditor(name, editor);
+                editPage.AddEditor(name, editor, prop.PropertyType);
             }
         }
         

+ 1 - 0
inabox.wpf/DynamicGrid/DynamicEditorForm/EmbeddedDynamicEditorForm.xaml.cs

@@ -217,6 +217,7 @@ namespace InABox.DynamicGrid
         {
             InitializeComponent();
             ReadOnly = false;
+            Editor.Form = this;
         }
 
         public override void OnApplyTemplate()

+ 2 - 0
inabox.wpf/DynamicGrid/Editors/BaseDynamicEditorControl.cs

@@ -28,6 +28,8 @@ namespace InABox.DynamicGrid
             Color = Colors.LightYellow;
         }
 
+        public Type ValueType { get; set; }
+
         public Color Color
         {
             get => (Color)GetValue(ColorProperty);

+ 33 - 12
inabox.wpf/DynamicGrid/Editors/DynamicEditorControlFactory.cs

@@ -10,9 +10,9 @@ namespace InABox.DynamicGrid
     public static class DynamicEditorControlFactory
     {
 
-        private static Dictionary<Type, Type>? _editors;
+        private static Dictionary<Type, List<(Type valueType, Type editor)>>? _editors;
 
-        private static Dictionary<Type, Type> GetEditors()
+        private static Dictionary<Type, List<(Type valueType, Type editor)>> GetEditors()
         {
             if(_editors is null)
             {
@@ -21,48 +21,69 @@ namespace InABox.DynamicGrid
                     x => x.IsClass
                         && !x.IsAbstract
                         && !x.IsGenericType
-                        && x.IsSubclassOfRawGeneric(typeof(BaseDynamicEditorControl<>))))
+                        && x.IsSubclassOfRawGeneric(typeof(DynamicEditorControl<,>))))
                 {
-                    var baseClass = type.GetSuperclassDefinition(typeof(BaseDynamicEditorControl<>))!;
-                    var editor = baseClass.GenericTypeArguments[0];
+                    var editorClass = type.GetSuperclassDefinition(typeof(DynamicEditorControl<,>))!;
+                    var valueType = editorClass.GenericTypeArguments[0];
+                    var editor = editorClass.GenericTypeArguments[1];
                     if (editor == typeof(IBaseEditor) || editor.HasInterface<IBaseEditor>())
                     {
-                        _editors[editor] = type;
+                        _editors.GetValueOrAdd(editor).Add((valueType, type));
                     }
                 }
             }
             return _editors;
         }
 
-        private static bool GetControlType(Type editorType, [NotNullWhen(true)] out Type? TControl)
+        private static bool GetControlType(Type editorType, Type valueType, [NotNullWhen(true)] out Type? TControl)
         {
             var controls = GetEditors().Where(x => editorType == x.Key || editorType.IsAssignableTo(x.Key));
 
             Type? editType = null;
+            List<(Type valueType, Type editor)>? tControls = null;
+
             TControl = null;
             foreach(var control in controls)
             {
                 if(control.Key == editorType)
                 {
-                    TControl = control.Value;
-                    return true;
+                    tControls = control.Value;
+                    break;
                 }
                 if(TControl is null || editType!.IsAssignableTo(control.Key))
                 {
-                    (editType, TControl) = control;
+                    (editType, tControls) = control;
+                }
+            }
+
+            if (tControls is null) return false;
+
+            Type? _valueType = null;
+            foreach(var control in tControls)
+            {
+                if(control.valueType == valueType)
+                {
+                    TControl = control.editor;
+                    return true;
+                }
+                if(valueType.IsAssignableTo(control.valueType)
+                    && (_valueType is null || _valueType.IsAssignableTo(control.valueType)))
+                {
+                    (_valueType, TControl) = control;
                 }
             }
 
             return TControl is not null;
         }
 
-        public static BaseDynamicEditorControl? CreateControl(BaseEditor editor, IDynamicEditorHost host) 
+        public static BaseDynamicEditorControl? CreateControl(BaseEditor editor, Type valueType, IDynamicEditorHost host) 
         {
-            if (GetControlType(editor.GetType(), out var TControl))
+            if (GetControlType(editor.GetType(), valueType, out var TControl))
             {
                 var result = Activator.CreateInstance(TControl) as BaseDynamicEditorControl;
                 if (result != null)
                 {
+                    result.ValueType = valueType;
                     result.Host = host;
                     result.EditorDefinition = editor;
                 }

+ 122 - 63
inabox.wpf/DynamicGrid/Editors/EmbeddedListEditor/EmbeddedListEditorControl.cs

@@ -1,100 +1,159 @@
 using System;
 using System.Collections;
 using System.Collections.Generic;
+using System.Linq;
 using System.Windows;
 using System.Windows.Controls;
 using System.Windows.Media;
 using InABox.Core;
+using javax.swing;
 
-namespace InABox.DynamicGrid
+namespace InABox.DynamicGrid;
+
+public abstract class BaseEmbeddedListEditorControl<T> : DynamicEditorControl<T, EmbeddedListEditor>
 {
-    public class EmbeddedListEditorControl : DynamicEditorControl<string, EmbeddedListEditor>
-    {
-        
-        static EmbeddedListEditorControl()
-        {
-            //DynamicEditorControlFactory.Register<EmbeddedListEditorControl, EmbeddedListEditor>();
-        }
-        
-        private Button Editor;
+    private Button Editor;
 
-        private string _data = "";
+    private T _data = default;
 
-        public override void Configure()
-        {
-        }
+    public Action<IDynamicGrid>? CustomiseGrid;
+
+    protected abstract object? GetList(T data);
 
-        protected override FrameworkElement CreateEditor()
+    protected abstract T SetList(object? data);
+
+    protected abstract void CancelEdit();
+
+    public override void Configure()
+    {
+    }
+
+    protected override FrameworkElement CreateEditor()
+    {
+        Editor = new Button
         {
-            Editor = new Button
-            {
-                Content = EditorDefinition.Label,
-                HorizontalAlignment = HorizontalAlignment.Stretch,
-                VerticalAlignment = VerticalAlignment.Stretch,
-                VerticalContentAlignment = VerticalAlignment.Center,
-            };
-            Editor.Click += Editor_Click;
-
-            return Editor;
-        }
+            Content = EditorDefinition.Label,
+            HorizontalAlignment = HorizontalAlignment.Stretch,
+            VerticalAlignment = VerticalAlignment.Stretch,
+            VerticalContentAlignment = VerticalAlignment.Center,
+        };
+        Editor.Click += Editor_Click;
 
-        private void Editor_Click(object sender, RoutedEventArgs e)
+        return Editor;
+    }
+
+    private void Editor_Click(object sender, RoutedEventArgs e)
+    {
+        var gridtype = DynamicGridUtils.FindDynamicGrid(typeof(DynamicItemsListGrid<>), EditorDefinition.DataType);
+        var list = GetList(_data);
+        
+        var grid = (Activator.CreateInstance(gridtype) as IDynamicItemsListGrid)!;
+        grid.Items = list as IList;
+        if(grid.GetType().IsGenericType && grid.GetType().GetGenericTypeDefinition() == typeof(DynamicItemsListGrid<>))
         {
-            var listtype = typeof(List<>).MakeGenericType(EditorDefinition.DataType);
-            var list = Serialization.Deserialize(listtype, _data) ?? (IList)Activator.CreateInstance(listtype)!;
-            var gridtype = DynamicGridUtils.FindDynamicGrid(typeof(DynamicItemsListGrid<>), EditorDefinition.DataType);
-            
-            var grid = (Activator.CreateInstance(gridtype) as IDynamicItemsListGrid)!;
-            grid.Items = list as IList;
+            // This is not an overriden grid, so we can customise how we want.
+
             grid.Reconfigure(options =>
             {
-                options.AddRows = true;
+                options.AddRows = EditorDefinition.AddRows;
                 options.EditRows = true;
                 options.DeleteRows = true;
                 options.RecordCount = true;
                 if (EditorDefinition.DirectEdit)
                     options.DirectEdit = true;
             });
-            grid.Refresh(true, true);
-
-            EditorDefinition.CreateButtons(grid);
-            
-            var window = new DynamicContentDialog((FrameworkElement)grid);
-            if (window.ShowDialog() == true)
-            {
-                _data = Serialization.Serialize(grid.Items);
-                CheckChanged();
-            }
-
         }
+        CustomiseGrid?.Invoke(grid);
+        grid.Refresh(true, true);
 
-        public override int DesiredHeight()
-        {
-            return 25;
-        }
+        EditorDefinition.CreateButtons(grid);
 
-        public override int DesiredWidth()
+        var window = new DynamicContentDialog((FrameworkElement)grid)
         {
-            return 100;
-        }
-
-        protected override string RetrieveValue()
+            Title = $"Edit {ColumnName}",
+            CanSave = true
+        };
+        if (window.ShowDialog() == true)
         {
-            return _data;
+            _data = SetList(grid.Items);
+            CheckChanged();
         }
-
-        protected override void UpdateValue(string value)
+        else
         {
-            _data = value;
+            CancelEdit();
         }
 
-        public override void SetFocus()
-        {
-            Editor.Focus();
-        }
+    }
+
+    public override int DesiredHeight()
+    {
+        return 25;
+    }
+
+    public override int DesiredWidth()
+    {
+        return 100;
+    }
+
+    protected override T RetrieveValue()
+    {
+        return _data;
+    }
+
+    protected override void UpdateValue(T value)
+    {
+        _data = value;
+    }
 
-        public override void SetColor(Color color)
+    public override void SetFocus()
+    {
+        Editor.Focus();
+    }
+
+    public override void SetColor(Color color)
+    {
+    }
+}
+
+public class StringEmbeddedListEditorControl : BaseEmbeddedListEditorControl<string>
+{
+    protected override object? GetList(string data)
+    {
+        var listtype = typeof(List<>).MakeGenericType(EditorDefinition.DataType);
+        return Serialization.Deserialize(listtype, data) ?? (IList)Activator.CreateInstance(listtype)!;
+    }
+
+    protected override string SetList(object? data)
+    {
+        return Serialization.Serialize(data);
+    }
+
+    protected override void CancelEdit()
+    {
+    }
+}
+
+public class ListEmbeddedListEditorControl : BaseEmbeddedListEditorControl<IList>
+{
+    BaseObjectSnapshot<BaseObject>[]? Snapshots;
+    
+    protected override object? GetList(IList data)
+    {
+        Snapshots = data.Cast<BaseObject>().Select(x => x.TakeSnapshot()).ToArray();
+
+        return data;
+    }
+
+    protected override IList SetList(object? data)
+    {
+        return data as IList;
+    }
+
+    protected override void CancelEdit()
+    {
+        foreach(var snapshot in Snapshots)
         {
+            snapshot.ResetObject();
         }
     }
 }

+ 3 - 0
inabox.wpf/DynamicGrid/Editors/IDynamicEditorControl.cs

@@ -1,3 +1,4 @@
+using System;
 using System.Collections.Generic;
 using System.Configuration;
 using System.Windows;
@@ -40,5 +41,7 @@ namespace InABox.DynamicGrid
     public interface IDynamicEditorControl<T> : IDynamicEditorControl
     {
         public T Value { get; set; }
+
+        public Type ValueType { get; set; }
     }
 }