Browse Source

New dimensions editor and fixed to linked properties

Kenric Nugteren 2 years ago
parent
commit
0434e13fb4

+ 1 - 1
InABox.Core/CoreUtils.cs

@@ -2456,7 +2456,7 @@ namespace InABox.Core
         public static Dictionary<string, object?> GetValues(BaseObject item, IEnumerable<IProperty>? props = null)
         {
             var result = new Dictionary<string, object?>();
-            props ??= DatabaseSchema.Properties(item.GetType()).Where(x => !(x.Editor is NullEditor));
+            props ??= DatabaseSchema.Properties(item.GetType());//.Where(x => !(x.Editor is NullEditor));
             foreach (var prop in props)
                 if (prop is CustomProperty)
                     try

+ 4 - 0
InABox.Core/DatabaseSchema/DatabaseSchema.cs

@@ -164,6 +164,10 @@ namespace InABox.Core
                                 prop.PropertyType.Equals(typeof(BaseEditor)) ||
                                 prop.PropertyType.IsSubclassOf(typeof(BaseEditor)))
                             {
+                                if (prop.PropertyType.GetInterfaces().Contains(typeof(IEnclosedEntity)))
+                                {
+                                    //RegisterProperty(newProperty);
+                                }
                                 RegisterProperties(master, prop.PropertyType, name, newProperty);
                             }
                             else

+ 13 - 0
InABox.Core/DatabaseSchema/IProperty.cs

@@ -60,6 +60,19 @@ namespace InABox.Core
 
     public static class PropertyExtensions
     {
+        public static IProperty? GetParentWithEditor(this IProperty property)
+        {
+            if (property.Parent == null) return null;
+
+            var parent = property.Parent.GetParentWithEditor();
+            if (parent != null) return parent;
+            if (property.Parent.HasEditor)
+            {
+                return property.Parent;
+            }
+            return null;
+        }
+
         public static bool HasParentEditor(this IProperty property)
         {
             return property.Parent != null && (property.Parent.HasEditor || property.Parent.HasParentEditor());

+ 30 - 0
InABox.Core/Editors/DimensionsEditor.cs

@@ -0,0 +1,30 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace InABox.Core
+{
+    public class DimensionsEditor : BaseEditor
+    {
+        public Type DimensionsType { get; set; }
+
+        public bool AllowEditingUnit { get; set; } = true;
+
+        public DimensionsEditor(Type dimensionsType)
+        {
+            if (!typeof(IDimensions).IsAssignableFrom(dimensionsType))
+            {
+                throw new ArgumentException("Type must be an IDimensions", nameof(dimensionsType));
+            }
+            DimensionsType = dimensionsType;
+        }
+
+        protected override BaseEditor DoClone()
+        {
+            return new DimensionsEditor(DimensionsType)
+            {
+                AllowEditingUnit = AllowEditingUnit
+            };
+        }
+    }
+}

+ 95 - 18
InABox.DynamicGrid/DynamicEditorControl.cs

@@ -5,6 +5,7 @@ using System.Windows;
 using System.Windows.Controls;
 using System.Windows.Media;
 using InABox.Core;
+using static ICSharpCode.AvalonEdit.Document.TextDocumentWeakEventManager;
 
 namespace InABox.DynamicGrid
 {
@@ -15,6 +16,7 @@ namespace InABox.DynamicGrid
         string ColumnName { get; set; }
 
         bool Loaded { get; set; }
+        bool Changed { get; set; }
 
         BaseEditor EditorDefinition { get; set; }
 
@@ -30,9 +32,9 @@ namespace InABox.DynamicGrid
 
         void SetVisible(bool enabled);
 
-        void SetValue(object value);
+        void SetValue(string property, object? value);
 
-        object? GetValue();
+        object? GetValue(string property);
     }
 
     public interface ILookupEditorControl : IDynamicEditorControl
@@ -99,6 +101,9 @@ namespace InABox.DynamicGrid
         [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
         public bool Loaded { get; set; }
 
+        public abstract bool Changed { get; set; }
+
+
         public virtual event EditorControlValueChangedHandler OnEditorValueChanged;
         public abstract int DesiredHeight();
 
@@ -112,9 +117,16 @@ namespace InABox.DynamicGrid
 
         public abstract void SetVisible(bool visible);
 
-        public abstract void SetValue(object? value);
+        public abstract void SetValue(string property, object? value);
 
-        public abstract object? GetValue();
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="property">The full property name of the entity being edited.</param>
+        /// <returns></returns>
+        public abstract object? GetValue(string property);
+
+        public abstract Dictionary<string, object?> GetValues();
 
         public new bool IsEnabled
         {
@@ -182,24 +194,18 @@ namespace InABox.DynamicGrid
         //    set { SetValue(OnEditorValueChangedProperty, value) }
         //}
 
-        protected bool _changed;
-
-        private bool Updating;
+        protected bool Updating;
 
         public DynamicEditorControl()
         {
             Loaded = false;
-            OtherValues = new Dictionary<string, object>();
+            OtherValues = new();
             MinHeight = 25;
             Focusable = false;
         }
 
         [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
-        public bool Changed
-        {
-            get => _changed;
-            set => _changed = value;
-        }
+        public override bool Changed { get; set; }
 
         [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
         public T Value
@@ -216,7 +222,9 @@ namespace InABox.DynamicGrid
 
         public override event EditorControlValueChangedHandler OnEditorValueChanged;
 
-        protected bool CheckChanged()
+        protected void EditorValueChanged(IDynamicEditorControl sender, Dictionary<string, object> values) => OnEditorValueChanged?.Invoke(sender, values);
+
+        protected virtual bool CheckChanged()
         {
             //Logger.Send(LogType.Information, "", string.Format("{0}({1}).CheckChanged()", GetType().EntityName().Split('.').Last(), ColumnName));
             if (Loaded && !Updating)
@@ -241,16 +249,24 @@ namespace InABox.DynamicGrid
             return Changed;
         }
 
-        public override void SetValue(object? value)
+        public override void SetValue(string property, object? value)
         {
             UpdateValue(value != null ? (T)value : default);
         }
 
-        public override object? GetValue()
+        public override object? GetValue(string property)
         {
             return RetrieveValue();
         }
 
+        public override Dictionary<string, object?> GetValues()
+        {
+            return new Dictionary<string, object?>
+            {
+                { ColumnName, RetrieveValue() }
+            };
+        }
+
         protected abstract T RetrieveValue();
         protected abstract void UpdateValue(T value);
 
@@ -261,8 +277,68 @@ namespace InABox.DynamicGrid
 
         public override void SetEnabled(bool enabled)
         {
-            var element = Content as FrameworkElement;
-            element.IsEnabled = enabled;
+            if (Content is FrameworkElement element) element.IsEnabled = enabled;
+            SetColor(enabled ? Color : Colors.WhiteSmoke);
+        }
+
+        public override void SetVisible(bool visible)
+        {
+            Visibility = visible ? Visibility.Visible : Visibility.Collapsed;
+        }
+    }
+
+    public abstract class DynamicEnclosedEditorControl<T> : BaseDynamicEditorControl
+        where T : IEnclosedEntity
+    {
+        protected bool Updating;
+
+        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
+        public override bool Changed { get; set; }
+
+        public override event EditorControlValueChangedHandler? OnEditorValueChanged;
+
+        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
+        protected virtual Dictionary<string, object?> OtherValues { get; }
+
+        public DynamicEnclosedEditorControl()
+        {
+            Loaded = false;
+            OtherValues = new();
+            MinHeight = 25;
+            Focusable = false;
+        }
+
+        protected virtual bool CheckChanged()
+        {
+            //Logger.Send(LogType.Information, "", string.Format("{0}({1}).CheckChanged()", GetType().EntityName().Split('.').Last(), ColumnName));
+            if (Loaded && !Updating)
+            {
+                Updating = true;
+                try
+                {
+                    var values = new Dictionary<string, object>();
+                    var sColumn = string.IsNullOrEmpty(ColumnName) ? "" : ColumnName;
+                    foreach(var (k, v) in GetValues())
+                    {
+                        values[k] = v;
+                    }
+                    foreach (var key in OtherValues.Keys)
+                        values[key] = OtherValues[key];
+                    OnEditorValueChanged?.Invoke(this, values);
+                }
+                finally
+                {
+                    Changed = true;
+                    Updating = false;
+                }
+            }
+
+            return Changed;
+        }
+
+        public override void SetEnabled(bool enabled)
+        {
+            if(Content is FrameworkElement element) element.IsEnabled = enabled;
             SetColor(enabled ? Color : Colors.WhiteSmoke);
         }
 
@@ -270,5 +346,6 @@ namespace InABox.DynamicGrid
         {
             Visibility = visible ? Visibility.Visible : Visibility.Collapsed;
         }
+
     }
 }

+ 4 - 0
InABox.DynamicGrid/DynamicEditorForm.xaml.cs

@@ -65,6 +65,8 @@ namespace InABox.DynamicGrid
             Func<Type, CoreTable>? pageDataHandler = null, bool preloadPages = false);
 
         IDynamicEditorControl FindEditor(string columnName);
+        object? GetEditorValue(string columnName);
+        void SetEditorValue(string columnName, object? value);
 
         void SetLayoutType<T>() where T : DynamicEditorGridLayout;
 
@@ -151,6 +153,8 @@ namespace InABox.DynamicGrid
 
 
         public IDynamicEditorControl FindEditor(string columnName) => Form.FindEditor(columnName);
+        public object? GetEditorValue(string columnName) => Form.GetEditorValue(columnName);
+        public void SetEditorValue(string columnName, object? value) => Form.SetEditorValue(columnName, value);
 
         public void UnloadEditorPages(bool saved) => Form.UnloadEditorPages(saved);
 

+ 44 - 16
InABox.DynamicGrid/DynamicEditorGrid.xaml.cs

@@ -8,6 +8,7 @@ using System.Windows.Media;
 using InABox.Clients;
 using InABox.Core;
 using InABox.WPF;
+using RoslynPad.Editor;
 
 namespace InABox.DynamicGrid
 {
@@ -160,9 +161,7 @@ namespace InABox.DynamicGrid
 
             public void AddEditor(string columnName, BaseEditor editor)
             {
-                BaseDynamicEditorControl? element = null;
-
-                element = editor switch
+                BaseDynamicEditorControl? element = editor switch
                 {
                     TextBoxEditor => new TextBoxEditorControl(),
                     Core.RichTextEditor => new RichTextEditorControl(),
@@ -225,6 +224,7 @@ namespace InABox.DynamicGrid
                     ColorEditor => new ColorEditorControl(),
                     FilterEditor filter => new FilterEditorControl { FilterType = filter.Type! },
                     ExpressionEditor expression => new ExpressionEditorControl(expression),
+                    DimensionsEditor dimension => DimensionsEditorControl.Create(dimension),
                     _ => null,
                 };
                 if (element != null)
@@ -332,6 +332,7 @@ namespace InABox.DynamicGrid
             public bool TryFindEditor(string columnname, [NotNullWhen(true)] out IDynamicEditorControl? editor)
             {
                 editor = Editors.FirstOrDefault(x => x.ColumnName.Equals(columnname));
+                editor ??= Editors.FirstOrDefault(x => columnname.StartsWith(x.ColumnName));
                 return editor is not null;
             }
 
@@ -550,7 +551,7 @@ namespace InABox.DynamicGrid
                 {
                     if (columns != null)
                         foreach (var (change, value) in columns)
-                            if (Editors.Any(x => x.ColumnName.Equals(change)) && !changededitors.ContainsKey(change) && !change.Equals(sender.ColumnName))
+                            if (!changededitors.ContainsKey(change) && !change.Equals(sender.ColumnName))
                                 changededitors[change] = value;
                 }
 
@@ -574,16 +575,14 @@ namespace InABox.DynamicGrid
                 var columnnames = changededitors != null ? changededitors.Keys.ToArray() : Editors.Select(x => x.ColumnName).ToArray();
                 foreach (var columnname in columnnames)
                 {
-                    var editor = Editors.FirstOrDefault(x => x.ColumnName.Equals(columnname));
-
-                    if (editor == null)
+                    if (!TryFindEditor(columnname, out var editor))
                         continue;
 
                     var bLoaded = editor.Loaded;
                     editor.Loaded = false;
                     if (changededitors != null && changededitors.ContainsKey(columnname))
                     {
-                        CoreUtils.SetPropertyValue(editor, "Value", changededitors[columnname]);
+                        editor.SetValue(columnname, changededitors[columnname]);
                     }
                     else
                     {
@@ -591,14 +590,14 @@ namespace InABox.DynamicGrid
 
                         try
                         {
-                            CoreUtils.SetPropertyValue(editor, "Value", curvalue);
+                            editor.SetValue(columnname, curvalue);
                         }
                         catch (Exception e)
                         {
                             MessageBox.Show($"Unable to set editor value for {columnname} -> {curvalue}: {CoreUtils.FormatException(e)}");
                         }
 
-                        CoreUtils.SetPropertyValue(editor, "Changed", false);
+                        editor.Changed = false;
                     }
 
                     editor.Loaded = bLoaded;
@@ -614,13 +613,15 @@ namespace InABox.DynamicGrid
 
                 foreach (var editor in Editors)
                 {
-                    var editorValue = editor.GetValue();
-                    var entityValue = EditorGrid.GetPropertyValue(editor.ColumnName);
-                    if (!Equals(editorValue, entityValue))
+                    foreach(var (column, editorValue) in editor.GetValues())
                     {
-                        editor.Loaded = false;
-                        editor.SetValue(entityValue);
-                        editor.Loaded = true;
+                        var entityValue = EditorGrid.GetPropertyValue(column);
+                        if (!Equals(editorValue, entityValue))
+                        {
+                            editor.Loaded = false;
+                            editor.SetValue(column, entityValue);
+                            editor.Loaded = true;
+                        }
                     }
                 }
 
@@ -708,6 +709,33 @@ namespace InABox.DynamicGrid
 
                     editPage.AddEditor(column.ColumnName, editor);
                 }
+                else if (iProp?.HasParentEditor() == true)
+                {
+                    var parent = iProp.GetParentWithEditor();
+                    if(parent is not null)
+                    {
+                        var parentEditor = parent.Editor;
+
+                        if(parentEditor is not null)
+                        {
+                            OnGridCustomiseEditor?.Invoke(this, new DynamicGridColumn { ColumnName = parent.Name }, parentEditor);
+                        }
+                        if(parentEditor is not null && parentEditor.Editable != Editable.Hidden)
+                        {
+                            var page = string.IsNullOrWhiteSpace(parentEditor.Page)
+                                ? parent is StandardProperty
+                                    ? "General"
+                                    : "Custom Fields"
+                                : parentEditor.Page;
+
+                            var editPage = GetEditPage(page);
+                            if (!editPage.TryFindEditor(parent.Name, out var editorControl))
+                            {
+                                editPage.AddEditor(parent.Name, parentEditor);
+                            }
+                        }
+                    }
+                }
             }
             
             OnEditorCreated?.Invoke(this, 0, 800);

+ 2 - 16
InABox.DynamicGrid/DynamicGrid.cs

@@ -2578,20 +2578,6 @@ namespace InABox.DynamicGrid
             return editor.ShowDialog() == true;
         }
 
-        private void UpdateEditor(DynamicEditorGrid grid, Expression<Func<IDimensioned, object?>> property, bool enabled)
-        {
-            if (!grid.TryFindEditor(new Column<IDimensioned>(property).Property, out var editor))
-                return;
-            editor.IsEnabled = enabled;
-            if (!enabled)
-                editor.SetValue(0D);
-            else
-            {
-                var value = editor.GetValue();
-                editor.SetValue(value);
-            }
-        }
-
         private Dictionary<String, object?> AfterEditorValueChanged(DynamicEditorGrid grid, T[] items, String columnnname)
         {
             var changes = new Dictionary<String, object?>();
@@ -2605,14 +2591,14 @@ namespace InABox.DynamicGrid
 
         protected virtual void ReconfigureEditors(DynamicEditorGrid grid, T[] items)
         {
-            if (items.First() is IDimensioned dimensioned)
+            /*if (items.First() is IDimensioned dimensioned)
             {
                 UpdateEditor(grid, x => x.Dimensions.Quantity, dimensioned.Dimensions.GetUnit().HasQuantity);
                 UpdateEditor(grid, x => x.Dimensions.Length, dimensioned.Dimensions.GetUnit().HasLength);
                 UpdateEditor(grid, x => x.Dimensions.Width, dimensioned.Dimensions.GetUnit().HasWidth);
                 UpdateEditor(grid, x => x.Dimensions.Height, dimensioned.Dimensions.GetUnit().HasHeight);
                 UpdateEditor(grid, x => x.Dimensions.Weight, dimensioned.Dimensions.GetUnit().HasWeight);
-            }
+            }*/
         }
 
         private string[]? ValidateData(T[] items)

+ 1 - 1
InABox.DynamicGrid/DynamicGridUtils.cs

@@ -365,7 +365,7 @@ namespace InABox.DynamicGrid
             var sw = new Stopwatch();
 
             var changes = new Dictionary<String, object?>(); 
-            var props = DatabaseSchema.Properties(items.First().GetType()).Where(x => x.Editor is not NullEditor).ToArray();
+            var props = DatabaseSchema.Properties(items.First().GetType()).ToArray();
             foreach (var item in items)
             {
                 //Dictionary<String, object> previous = new Dictionary<string, object>();

+ 256 - 0
InABox.DynamicGrid/Editors/DimensionsEditor.cs

@@ -0,0 +1,256 @@
+using InABox.Clients;
+using InABox.Core;
+using Syncfusion.Windows.Shared;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Media;
+
+namespace InABox.DynamicGrid
+{
+    public class DimensionsEditorControl
+    {
+        public static BaseDynamicEditorControl? Create(DimensionsEditor editor)
+        {
+            var dimensionsType = editor.DimensionsType;
+            var dimensions = dimensionsType.GetSuperclassDefinition(typeof(Dimensions<,>));
+            if (dimensions == null) return null;
+
+            var tLink = dimensions.GenericTypeArguments[0];
+            var tUnit = dimensions.GenericTypeArguments[1];
+
+            return Activator.CreateInstance(typeof(DimensionsEditorControl<,,>).MakeGenericType(dimensionsType, tLink, tUnit), editor) as BaseDynamicEditorControl;
+        }
+    }
+
+    public class DimensionsEditorControl<TDimensions, TLink, TUnit> : DynamicEnclosedEditorControl<TDimensions>
+        where TDimensions : Dimensions<TLink, TUnit>, new()
+        where TLink : DimensionUnitLink<TUnit>, new()
+        where TUnit : DimensionUnit, new()
+    {
+        private Grid Grid;
+        private ComboBox Combo;
+
+        private DoubleTextBox Quantity;
+        private DoubleTextBox Length;
+        private DoubleTextBox Width;
+        private DoubleTextBox Height;
+        private DoubleTextBox Weight;
+
+        private List<Tuple<string, TUnit>> Units;
+
+        private DimensionsEditor Editor;
+
+        public DimensionsEditorControl(DimensionsEditor editor)
+        {
+            Editor = editor;
+        }
+
+        public override int DesiredHeight()
+        {
+            return 25;
+        }
+
+        public override int DesiredWidth()
+        {
+            return int.MaxValue;
+        }
+
+        public override void SetColor(Color color)
+        {
+            Quantity.Background = new SolidColorBrush(color);
+            Length.Background = new SolidColorBrush(color);
+            Width.Background = new SolidColorBrush(color);
+            Height.Background = new SolidColorBrush(color);
+            Weight.Background = new SolidColorBrush(color);
+        }
+
+        public override void SetFocus()
+        {
+            Combo.Focus();
+        }
+
+        protected override FrameworkElement CreateEditor()
+        {
+            Grid = new Grid
+            {
+                VerticalAlignment = VerticalAlignment.Stretch,
+                HorizontalAlignment = HorizontalAlignment.Stretch
+            };
+            Grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(150, GridUnitType.Pixel) });
+
+            Combo = new ComboBox
+            {
+                IsEnabled = Editor.AllowEditingUnit
+            };
+            Combo.SetValue(Grid.ColumnProperty, 0);
+            Combo.SetValue(Grid.RowProperty, 0);
+
+            Grid.Children.Add(Combo);
+
+            var result = new Client<TUnit>()
+                .Query(
+                    LookupFactory.DefineFilter<TUnit>(),
+                    LookupFactory.DefineColumns<TUnit>(),
+                    LookupFactory.DefineSort<TUnit>());
+
+            Units = result.Rows.Select(row =>
+            {
+                var values = row.ToDictionary(new[] { "Display" });
+                var display = LookupFactory.FormatLookup(typeof(TUnit), values, Array.Empty<string>());
+                return new Tuple<string, TUnit>(display, row.ToObject<TUnit>());
+            }).ToList();
+
+            Combo.DisplayMemberPath = "Item1";
+            Combo.SelectedValuePath = "Item2.ID";
+            Combo.ItemsSource = Units;
+            Combo.SelectionChanged += Combo_SelectionChanged;
+
+            Quantity = AddDimension("Quantity: ", 1);
+            Length = AddDimension("Length: ", 2);
+            Width = AddDimension("Width: ", 3);
+            Height = AddDimension("Height: ", 4);
+            Weight = AddDimension("Weight: ", 5);
+
+            return Grid;
+        }
+
+        private void UpdateColumn(int column, bool visible, DoubleTextBox box)
+        {
+            if (!visible)
+            {
+                box.Value = 0.0;
+            }
+
+            var columnDefinition = Grid.ColumnDefinitions[column * 2];
+            if (visible)
+            {
+                columnDefinition.Width = new GridLength(1, GridUnitType.Star);
+            }
+            else
+            {
+                columnDefinition.Width = new GridLength(0);
+            }
+            columnDefinition = Grid.ColumnDefinitions[column * 2 - 1];
+            if (visible)
+            {
+                columnDefinition.Width = GridLength.Auto;
+            }
+            else
+            {
+                columnDefinition.Width = new GridLength(0);
+            }
+        }
+
+        private DoubleTextBox AddDimension(string name, int column)
+        {
+            Grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(0) });
+            Grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(0) });
+
+            var label = new Label
+            {
+                Content = name,
+                VerticalAlignment = VerticalAlignment.Center,
+                VerticalContentAlignment = VerticalAlignment.Center,
+                Margin = new Thickness(5, 0, 0, 0)
+            };
+            label.SetValue(Grid.ColumnProperty, column * 2 - 1);
+
+            var box = new DoubleTextBox
+            {
+                VerticalAlignment = VerticalAlignment.Stretch,
+                VerticalContentAlignment = VerticalAlignment.Center,
+                HorizontalAlignment = HorizontalAlignment.Stretch,
+                HorizontalContentAlignment = HorizontalAlignment.Center,
+                NumberDecimalDigits = 2,
+                Margin = new Thickness(5, 0, 0, 0)
+            };
+            box.SetValue(Grid.ColumnProperty, column * 2);
+            box.ValueChanged += Box_ValueChanged;
+
+            Grid.Children.Add(label);
+            Grid.Children.Add(box);
+
+            return box;
+        }
+
+        private void Box_ValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+        {
+            CheckChanged();
+        }
+
+        private void Combo_SelectionChanged(object sender, SelectionChangedEventArgs e)
+        {
+            if (Combo.SelectedValue is not Guid unitID) return;
+            if (Combo.SelectedItem is not Tuple<string, TUnit> tuple) return;
+            var unit = tuple.Item2;
+
+            UpdateColumn(1, unit.HasQuantity, Quantity);
+            UpdateColumn(2, unit.HasLength, Length);
+            UpdateColumn(3, unit.HasWidth, Width);
+            UpdateColumn(4, unit.HasHeight, Height);
+            UpdateColumn(5, unit.HasWeight, Weight);
+
+            foreach(var property in DatabaseSchema.Properties(typeof(TUnit)))
+            {
+                var value = property.Getter()(unit);
+                OtherValues[$"{ColumnName}.Unit.{property.Name}"] = value;
+            }
+
+            CheckChanged();
+        }
+
+        public override object? GetValue(string property)
+        {
+            if (!property.StartsWith($"{ColumnName}.")) return null;
+            property = property[(ColumnName.Length + 1)..];
+
+            if (property == "Quantity") return Quantity.Value ?? 0.0;
+            if (property == "Length") return Length.Value ?? 0.0;
+            if (property == "Width") return Width.Value ?? 0.0;
+            if (property == "Height") return Height.Value ?? 0.0;
+            if (property == "Weight") return Weight.Value ?? 0.0;
+            if (property == "Unit.ID") return Combo.SelectedValue is Guid guid ? guid : Guid.Empty;
+
+            return null;
+        }
+        public override Dictionary<string, object?> GetValues()
+        {
+            var values = new Dictionary<string, object?>
+            {
+                {$"{ColumnName}.Quantity", Quantity.Value ?? 0.0},
+                {$"{ColumnName}.Length", Length.Value ?? 0.0},
+                {$"{ColumnName}.Width", Width.Value ?? 0.0},
+                {$"{ColumnName}.Height", Height.Value ?? 0.0},
+                {$"{ColumnName}.Weight", Weight.Value ?? 0.0},
+                {$"{ColumnName}.Unit.ID", Combo.SelectedValue is Guid guid ? guid : Guid.Empty }
+            };
+            return values;
+        }
+
+        public override void SetValue(string property, object? value)
+        {
+            if (!property.StartsWith($"{ColumnName}.")) return;
+            property = property[(ColumnName.Length + 1)..];
+
+            if (value is null) return;
+
+            if (property == "Unit.ID")
+            {
+                Combo.SelectedValue = value is Guid guid ? guid : Guid.Empty;
+                return;
+            }
+
+            if (property == "Quantity") Quantity.Value = (double)value;
+            if (property == "Length") Length.Value = (double)value;
+            if (property == "Width") Width.Value = (double)value;
+            if (property == "Height") Height.Value = (double)value;
+            if (property == "Weight") Weight.Value = (double)value;
+        }
+
+    }
+}

+ 2 - 0
InABox.DynamicGrid/EmbeddedDynamicEditorForm.xaml.cs

@@ -408,6 +408,8 @@ namespace InABox.DynamicGrid
         {
             return Editor.FindEditor(columnname);
         }
+        public object? GetEditorValue(string columnName) => FindEditor(columnName).GetValue(columnName);
+        public void SetEditorValue(string columnName, object? value) => FindEditor(columnName).SetValue(columnName, value);
 
         public void SetLayoutType<T>() where T : DynamicEditorGridLayout => Editor.SetLayoutType<T>();