Procházet zdrojové kódy

Merge remote-tracking branch 'origin/kenric' into frank

frankvandenbos před 8 měsíci
rodič
revize
6b8931c5de

+ 0 - 44
inabox.wpf/DynamicGrid/Aggregates/DynamicGridDoubleAggregate.cs

@@ -1,44 +0,0 @@
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.Data;
-using System.Linq;
-using InABox.Core;
-using Syncfusion.Data;
-
-namespace InABox.DynamicGrid;
-
-public class DynamicGridDoubleAggregate : ISummaryAggregate
-{
-    public int Count { get; private set; }
-
-    public double Sum { get; private set; }
-
-    public Action<IEnumerable, string, PropertyDescriptor> CalculateAggregateFunc()
-    {
-        return CalculateAggregate;
-    }
-
-    private void CalculateAggregate(IEnumerable items, string property, PropertyDescriptor args)
-    {
-        if (items is IEnumerable<DataRowView> rows)
-        {
-            if (string.Equals(args.Name, "Count"))
-            {
-                Count = rows.Count();
-            }
-            else if (string.Equals(args.Name, "Sum"))
-            {
-                Sum = 0;
-                foreach (var row in rows)
-                    if (row[property] is TimeSpan)
-                        Sum += (double)row[property];
-            }
-        }
-        else
-        {
-            Logger.Send(LogType.Error, "", $"Attempting to calculate aggregate on invalid data type '{items.GetType()}'.");
-        }
-    }
-}

+ 2 - 2
inabox.wpf/DynamicGrid/Aggregates/DynamicGridDurationAggregate.cs

@@ -32,8 +32,8 @@ public class DynamicGridDurationAggregate : IDynamicGridSummaryAggregate
             {
                 Sum = new TimeSpan();
                 foreach (var row in rows)
-                    if (row[property] is TimeSpan)
-                        Sum += (TimeSpan)row[property];
+                    if (row[property] is TimeSpan t)
+                        Sum += t;
             }
         }
         else

+ 0 - 44
inabox.wpf/DynamicGrid/Aggregates/DynamicGridIntegerAggregate.cs

@@ -1,44 +0,0 @@
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.Data;
-using System.Linq;
-using InABox.Core;
-using Syncfusion.Data;
-
-namespace InABox.DynamicGrid;
-
-public class DynamicGridIntegerAggregate : ISummaryAggregate
-{
-    public int Count { get; private set; }
-
-    public int Sum { get; private set; }
-
-    public Action<IEnumerable, string, PropertyDescriptor> CalculateAggregateFunc()
-    {
-        return CalculateAggregate;
-    }
-
-    private void CalculateAggregate(IEnumerable items, string property, PropertyDescriptor args)
-    {
-        if (items is IEnumerable<DataRowView> rows)
-        {
-            if (string.Equals(args.Name, "Count"))
-            {
-                Count = rows.Count();
-            }
-            else if (string.Equals(args.Name, "Sum"))
-            {
-                Sum = 0;
-                foreach (var row in rows)
-                    if (row[property] is TimeSpan)
-                        Sum += (int)row[property];
-            }
-        }
-        else
-        {
-            Logger.Send(LogType.Error, "", $"Attempting to calculate aggregate on invalid data type '{items.GetType()}'.");
-        }
-    }
-}

+ 50 - 0
inabox.wpf/DynamicGrid/Aggregates/DynamicGridSummary.cs

@@ -0,0 +1,50 @@
+using InABox.Core;
+using Org.BouncyCastle.Asn1.X509.Qualified;
+using Syncfusion.UI.Xaml.Grid;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+
+namespace InABox.DynamicGrid;
+
+public interface IDynamicGridSummary
+{
+}
+
+public class DynamicGridCountSummary : IDynamicGridSummary
+{
+}
+
+public abstract class DynamicGridSumSummary(string format) : IDynamicGridSummary
+{
+    public string Format { get; set; } = format;
+
+    public abstract Type AggregateType { get; }
+}
+
+public class DynamicGridSumSummary<TAggregate>(string format) : DynamicGridSumSummary(format)
+{
+    public string Format { get; set; } = format;
+
+    public override Type AggregateType => typeof(TAggregate);
+}
+
+public class DynamicGridCustomSummary(DynamicGridCustomSummary.AggregateFunc aggregate, string format) : IDynamicGridSummary
+{
+    public delegate object AggregateFunc(IEnumerable<CoreRow> rows);
+
+    public AggregateFunc Aggregate { get; set; } = aggregate;
+
+    public string Format { get; set; } = format;
+}
+
+public class DynamicGridTemplateSummary(Func<FrameworkElement?> template) : IDynamicGridSummary
+{
+    public Func<FrameworkElement?> Template { get; set; } = template;
+}

+ 2 - 2
inabox.wpf/DynamicGrid/Columns/DynamicActionColumn.cs

@@ -21,7 +21,7 @@ namespace InABox.DynamicGrid
 
         public ActionColumnToolTip? ToolTip { get; set; }
 
-        public Func<GridSummaryColumn?>? GetSummary = null;
+        public Func<IDynamicGridSummary?>? GetSummary = null;
         
         public string[]? ExcludeFilters { get; set; }
         public string[]? SelectedFilters { get; set; }
@@ -69,6 +69,6 @@ namespace InABox.DynamicGrid
 
         public abstract object? Data(CoreRow? row);
 
-        public GridSummaryColumn? Summary() => GetSummary?.Invoke();
+        public IDynamicGridSummary? Summary() => GetSummary?.Invoke();
     }
 }

+ 5 - 17
inabox.wpf/DynamicGrid/Columns/EditorColumns/DynamicGridCurrencyColumn.cs

@@ -50,26 +50,14 @@ public class DynamicGridCurrencyColumn<TEntity> : DynamicGridNumericColumn<TEnti
             });
     }
 
-    public override GridSummaryColumn? Summary()
+    public override IDynamicGridSummary? Summary()
     {
-        if (Definition == null || Definition.Editor.Summary == Core.Summary.None)
+        if (Definition.Editor.Summary == Core.Summary.None)
             return null;
         
-        var format = Definition.Editor.Summary == Core.Summary.Count
-            ? "N0"
-            : $"C{Editor!.Digits}";
-                            
-        var summary = new GridSummaryColumn
-        {
-            Name = MappingName,
-            Format = "{" + (Definition.Editor.Summary == Core.Summary.Sum ? "Sum" : "Count") + ":" + format + "}",
-            MappingName = MappingName,
-            SummaryType = Definition.Editor.Summary == Core.Summary.Sum
-                ? SummaryType.DoubleAggregate
-                : SummaryType.CountAggregate,
-            CustomAggregate = new DynamicGridDoubleAggregate()
-        };
-        return summary;
+        return Definition.Editor.Summary == Core.Summary.Sum
+            ? new DynamicGridSumSummary<double>($"C{Editor!.Digits}")
+            : new DynamicGridCountSummary();
     }
 
     public DynamicGridCurrencyColumn(DynamicGridColumn definition) : base(definition)

+ 2 - 2
inabox.wpf/DynamicGrid/Columns/EditorColumns/DynamicGridDateColumn.cs

@@ -15,10 +15,10 @@ public class DynamicGridDateColumn<TEntity> : DynamicGridMaskColumn<TEntity,Date
     where TEntity : BaseObject
 {
     protected override Behavior CreateBehaviour() => 
-        new TextBoxDateMaskBehavior(Definition?.Format);
+        new TextBoxDateMaskBehavior(Definition.Format);
 
     protected override IValueConverter CreateConverter() =>
-        new DateToStringConverter(Definition?.Format);
+        new DateToStringConverter(Definition.Format);
     
     protected override void UpdateButtons(object? value, DynamicGridMaskColumnButton[]? buttons)
     {

+ 2 - 2
inabox.wpf/DynamicGrid/Columns/EditorColumns/DynamicGridDateTimeColumn.cs

@@ -16,10 +16,10 @@ public class DynamicGridDateTimeColumn<TEntity> : DynamicGridMaskColumn<TEntity,
     where TEntity : BaseObject
 {
     protected override Behavior CreateBehaviour() => 
-        new TextBoxDateTimeMaskBehavior(Definition?.Format);
+        new TextBoxDateTimeMaskBehavior(Definition.Format);
 
     protected override IValueConverter CreateConverter() =>
-        new DateTimeToStringConverter(Definition?.Format);
+        new DateTimeToStringConverter(Definition.Format);
     
     protected override void UpdateButtons(object? value, DynamicGridMaskColumnButton[]? buttons)
     {

+ 5 - 17
inabox.wpf/DynamicGrid/Columns/EditorColumns/DynamicGridDoubleColumn.cs

@@ -25,26 +25,14 @@ public class DynamicGridDoubleColumn<TEntity> : DynamicGridNumericColumn<TEntity
         column.NumberGroupSizes = new Int32Collection(new[] { 3, 3, 3, 3, 3, 3 });
     }
     
-    public override GridSummaryColumn? Summary()
+    public override IDynamicGridSummary? Summary()
     {
-        if (Definition == null || Definition.Editor.Summary == Core.Summary.None)
+        if (Definition.Editor.Summary == Core.Summary.None)
             return null;
         
-        var format = Definition.Editor.Summary == Core.Summary.Count
-            ? "N0"
-            : $"N{Editor!.Digits}";
-                            
-        var summary = new GridSummaryColumn
-        {
-            Name = MappingName,
-            Format = "{" + (Definition.Editor.Summary == Core.Summary.Sum ? "Sum" : "Count") + ":" + format + "}",
-            MappingName = MappingName,
-            SummaryType = Definition.Editor.Summary == Core.Summary.Sum
-                ? SummaryType.DoubleAggregate
-                : SummaryType.CountAggregate,
-            CustomAggregate = new DynamicGridDoubleAggregate()
-        };
-        return summary;
+        return Definition.Editor.Summary == Core.Summary.Sum
+            ? new DynamicGridSumSummary<double>($"N{Editor!.Digits}")
+            : new DynamicGridCountSummary();
     }
 
     public DynamicGridDoubleColumn(DynamicGridColumn definition) : base(definition)

+ 7 - 22
inabox.wpf/DynamicGrid/Columns/EditorColumns/DynamicGridDurationColumn.cs

@@ -16,10 +16,10 @@ public class DynamicGridDurationColumn<TEntity> : DynamicGridMaskColumn<TEntity,
     where TEntity : BaseObject
 {
     protected override Behavior CreateBehaviour() => 
-        new TextBoxTimeSpanMaskBehavior(Definition?.Format);
+        new TextBoxTimeSpanMaskBehavior(Definition.Format);
 
     protected override IValueConverter CreateConverter() =>
-        new TimeSpanToStringConverter(Definition?.Format);
+        new TimeSpanToStringConverter(Definition.Format);
     
     private readonly BitmapImage _less = Wpf.Resources.downarrow.AsBitmapImage(20,20);
     private readonly BitmapImage _more = Wpf.Resources.uparrow.AsBitmapImage(20,20);
@@ -59,29 +59,14 @@ public class DynamicGridDurationColumn<TEntity> : DynamicGridMaskColumn<TEntity,
         };
     }
     
-    public override GridSummaryColumn? Summary()
+    public override IDynamicGridSummary? Summary()
     {
-        
-        if (Definition == null || Definition.Editor.Summary == Core.Summary.None)
+        if (Definition.Editor.Summary == Core.Summary.None)
             return null;
         
-        var result = new GridSummaryColumn
-        {
-            Name = MappingName,
-            Format = "{" + (Definition.Editor.Summary == Core.Summary.Sum
-                ? "Sum" + (string.IsNullOrWhiteSpace(Definition.Format)
-                    ? ""
-                    : ":" + Definition.Format.Replace(":", "':'"))
-                : Definition.Editor.Summary == Core.Summary.Count
-                    ? "Count"
-                    : "") + "}",
-            MappingName = MappingName,
-            SummaryType = Definition.Editor.Summary == Core.Summary.Sum
-                ? SummaryType.Custom
-                : SummaryType.CountAggregate,
-            CustomAggregate = new DynamicGridDurationAggregate()
-        };
-        return result;
+        return Definition.Editor.Summary == Core.Summary.Sum
+            ? new DynamicGridSumSummary<TimeSpan>(Definition.Format.IsNullOrWhiteSpace() ? "" : Definition.Format.Replace(":", "':'"))
+            : new DynamicGridCountSummary();
     }
 
     public DynamicGridDurationColumn(DynamicGridColumn definition) : base(definition)

+ 34 - 38
inabox.wpf/DynamicGrid/Columns/EditorColumns/DynamicGridEditorColumn.cs

@@ -19,18 +19,18 @@ public abstract class DynamicGridEditorColumn<TEntity, TEditor, TGridColumn, TTr
     
     public List<string> ExtraColumns { get; } = new();
     
-    public string? MappingName => Definition?.ColumnName.Replace('.', '_');
+    public string MappingName => Definition.ColumnName.Replace('.', '_');
 
-    public string? TreeMappingName => $"[{Definition?.ColumnName}]";
+    public string TreeMappingName => $"[{Definition.ColumnName}]";
     
-    public Func<BaseObject>? GetEntity { get; set; }
+    public Func<BaseObject?>? GetEntity { get; set; }
     
     public void DoEntityChanged(string columnname, Dictionary<string,object?> changes)
     {
         EntityChanged?.Invoke(this, new DynamicColumnEntityChangedEventArgs(columnname, changes));
     }
 
-    public event DynamicColumnEntityChangedEvent EntityChanged;
+    public event DynamicColumnEntityChangedEvent? EntityChanged;
 
     public TGridColumn CreateGridColumn()
     {
@@ -81,21 +81,17 @@ public abstract class DynamicGridEditorColumn<TEntity, TEditor, TGridColumn, TTr
         Definition = definition;
     }
     
-    public DynamicGridColumn? Definition { get; set; }
+    public DynamicGridColumn Definition { get; set; }
 
-    public virtual GridSummaryColumn? Summary() => null;
+    public virtual IDynamicGridSummary? Summary() => null;
 
     public TEditor? Editor
     {
         get
         {
-            if (Definition != null)
-            {
-                if (Definition?.Editor is not TEditor result)
-                    result = CoreUtils.GetProperty<TEntity>(Definition.ColumnName)?.GetEditor() as TEditor;
-                return result;
-            }
-            return null;
+            if (Definition.Editor is not TEditor result)
+                result = CoreUtils.GetProperty<TEntity>(Definition.ColumnName)?.GetEditor() as TEditor;
+            return result;
         }
     }
 
@@ -108,40 +104,40 @@ public abstract class DynamicGridEditorColumn<TEntity, TEditor, TGridColumn, TTr
         column.MappingName = TreeMappingName;
     }
 
-    protected TextAlignment GetTextAlignment(TEditor editor) => Definition?.Alignment == Alignment.NotSet
+    protected TextAlignment GetTextAlignment(TEditor editor) => Definition.Alignment == Alignment.NotSet
         ? editor is NumericEditor ? TextAlignment.Right : TextAlignment.Left
-        : Definition?.Alignment == Alignment.BottomLeft || 
-          Definition?.Alignment == Alignment.MiddleLeft || 
-          Definition?.Alignment == Alignment.TopLeft
+        : Definition.Alignment == Alignment.BottomLeft || 
+          Definition.Alignment == Alignment.MiddleLeft || 
+          Definition.Alignment == Alignment.TopLeft
             ? TextAlignment.Left
-            : Definition?.Alignment == Alignment.BottomCenter ||
-              Definition?.Alignment == Alignment.MiddleCenter ||
-              Definition?.Alignment == Alignment.TopCenter
+            : Definition.Alignment == Alignment.BottomCenter ||
+              Definition.Alignment == Alignment.MiddleCenter ||
+              Definition.Alignment == Alignment.TopCenter
                 ? TextAlignment.Center
                 : TextAlignment.Right;
     
     
-    protected HorizontalAlignment GetHorizontalAlignment(TEditor editor) => Definition?.Alignment == Alignment.NotSet
+    protected HorizontalAlignment GetHorizontalAlignment(TEditor editor) => Definition.Alignment == Alignment.NotSet
         ? editor is NumericEditor ? HorizontalAlignment.Right : HorizontalAlignment.Left
-        : Definition?.Alignment == Alignment.BottomLeft || 
-          Definition?.Alignment == Alignment.MiddleLeft || 
-          Definition?.Alignment == Alignment.TopLeft
+        : Definition.Alignment == Alignment.BottomLeft || 
+          Definition.Alignment == Alignment.MiddleLeft || 
+          Definition.Alignment == Alignment.TopLeft
             ? HorizontalAlignment.Left
-            : Definition?.Alignment == Alignment.BottomCenter ||
-              Definition?.Alignment == Alignment.MiddleCenter ||
-              Definition?.Alignment == Alignment.TopCenter
+            : Definition.Alignment == Alignment.BottomCenter ||
+              Definition.Alignment == Alignment.MiddleCenter ||
+              Definition.Alignment == Alignment.TopCenter
                 ? HorizontalAlignment.Center
                 : HorizontalAlignment.Right;
 
-    protected VerticalAlignment GetVerticalAlignment(TEditor editor) => Definition?.Alignment == Alignment.NotSet
+    protected VerticalAlignment GetVerticalAlignment(TEditor editor) => Definition.Alignment == Alignment.NotSet
         ? VerticalAlignment.Center
-        : Definition?.Alignment == Alignment.TopLeft ||
-          Definition?.Alignment == Alignment.TopCenter ||
-          Definition?.Alignment == Alignment.TopRight
+        : Definition.Alignment == Alignment.TopLeft ||
+          Definition.Alignment == Alignment.TopCenter ||
+          Definition.Alignment == Alignment.TopRight
             ? VerticalAlignment.Top
-            : Definition?.Alignment == Alignment.MiddleLeft ||
-              Definition?.Alignment == Alignment.MiddleCenter ||
-              Definition?.Alignment == Alignment.MiddleRight
+            : Definition.Alignment == Alignment.MiddleLeft ||
+              Definition.Alignment == Alignment.MiddleCenter ||
+              Definition.Alignment == Alignment.MiddleRight
                 ? VerticalAlignment.Center
                 : VerticalAlignment.Bottom;
     
@@ -155,8 +151,8 @@ public abstract class DynamicGridEditorColumn<TEntity, TEditor, TGridColumn, TTr
         column.ColumnSizer =
             GridLengthUnitType
                 .None; //column.Width != 0 ? GridLengthUnitType.None : GridLengthUnitType.AutoWithLastColumnFill;
-        column.HeaderText = string.IsNullOrWhiteSpace(Definition?.Caption)
-            ? Definition?.ColumnName
+        column.HeaderText = string.IsNullOrWhiteSpace(Definition.Caption)
+            ? Definition.ColumnName
             : Definition.Caption;
 
         column.TextAlignment = GetTextAlignment(editor);
@@ -171,8 +167,8 @@ public abstract class DynamicGridEditorColumn<TEntity, TEditor, TGridColumn, TTr
         column.Width = column.Width; // != 0 ? column.Width : double.NaN;
 
         column.ColumnSizer = TreeColumnSizer.None;
-        column.HeaderText = string.IsNullOrWhiteSpace(Definition?.Caption)
-            ? Definition?.ColumnName
+        column.HeaderText = string.IsNullOrWhiteSpace(Definition.Caption)
+            ? Definition.ColumnName
             : Definition.Caption;
 
         column.TextAlignment = GetTextAlignment(editor);

+ 5 - 18
inabox.wpf/DynamicGrid/Columns/EditorColumns/DynamicGridIntegerColumn.cs

@@ -20,27 +20,14 @@ public class DynamicGridIntegerColumn<TEntity> : DynamicGridNumericColumn<TEntit
         column.NumberDecimalDigits = 0;
     }
     
-    public override GridSummaryColumn? Summary()
+    public override IDynamicGridSummary? Summary()
     {
-        if (Definition == null || Definition.Editor.Summary == Core.Summary.None)
+        if (Definition.Editor.Summary == Core.Summary.None)
             return null;
         
-        var format = Definition.Editor.Summary == Core.Summary.Count
-            ? "N0"
-            : $"N{Editor!.Digits}";
-                            
-        var summary = new GridSummaryColumn
-        {
-            Name = MappingName,
-            Format = "{" + (Definition.Editor.Summary == Core.Summary.Sum ? "Sum" : "Count") + ":" + format + "}",
-            MappingName = MappingName,
-            SummaryType = Definition.Editor.Summary == Core.Summary.Sum
-                ? SummaryType.Int32Aggregate 
-                : SummaryType.CountAggregate,
-            CustomAggregate = new DynamicGridIntegerAggregate()
-        };
-        
-        return summary;
+        return Definition.Editor.Summary == Core.Summary.Sum
+            ? new DynamicGridSumSummary<int>($"N{Editor!.Digits}")
+            : new DynamicGridCountSummary();
     }
 
     public DynamicGridIntegerColumn(DynamicGridColumn definition) : base(definition)

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

@@ -8,9 +8,9 @@ namespace InABox.DynamicGrid;
 
 public interface IDynamicGridEditorColumn : IDynamicColumnBase
 {
-    DynamicGridColumn? Definition { get; set; }
-    string? MappingName { get; }
-    string? TreeMappingName { get; }
+    DynamicGridColumn Definition { get; set; }
+    string MappingName { get; }
+    string TreeMappingName { get; }
     List<string> ExtraColumns { get; }
 
     bool VariableWidth { get; }
@@ -18,9 +18,9 @@ public interface IDynamicGridEditorColumn : IDynamicColumnBase
     bool Filtered { get; }
     bool Editable { get; }
 
-    GridSummaryColumn? Summary();
+    IDynamicGridSummary? Summary();
 
-    Func<BaseObject>? GetEntity { get; set; }
+    Func<BaseObject?>? GetEntity { get; set; }
 
     GridColumn CreateGridColumn();
     TreeGridColumn CreateTreeGridColumn();

+ 1 - 2
inabox.wpf/DynamicGrid/DynamicGridCommon.cs

@@ -16,8 +16,7 @@ public abstract class DynamicColumnBase : BaseObject, IDynamicColumnBase
 
     public event DynamicColumnEntityChangedEvent? EntityChanged;
     
-    public object? Tag { get; set;
-		}
+    public object? Tag { get; set; }
 }
 
 public enum DynamicGridOption

+ 93 - 4
inabox.wpf/DynamicGrid/UIComponent/DynamicGridGridUIComponent.cs

@@ -12,6 +12,7 @@ using Syncfusion.UI.Xaml.Grid.Cells;
 using Syncfusion.UI.Xaml.Grid.Helpers;
 using Syncfusion.UI.Xaml.ScrollAxis;
 using System;
+using System.Collections;
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
 using System.ComponentModel;
@@ -949,7 +950,7 @@ public class DynamicGridGridUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
                 var sColName = string.Format("ActionColumn{0}", i);
                 gridRowResizingOptions.ExcludeColumns.Add(sColName);
 
-                var summary = column.Summary();
+                var summary = ConvertSummary(column.Summary());
                 if (summary != null)
                 {
                     summary.Name = sColName;
@@ -1084,6 +1085,9 @@ public class DynamicGridGridUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
             }
         }
     }
+
+    #region Summaries
+
     public class SummaryRowStyleSelector(DynamicGridGridUIComponent<T> parent, Func<Style> selector) : StyleSelector
     {
         public DynamicGridGridUIComponent<T> Parent { get; init; } = parent;
@@ -1112,6 +1116,88 @@ public class DynamicGridGridUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
         }
     }
 
+    private GridSummaryColumn? ConvertSummary(IDynamicGridSummary? summary)
+    {
+        if(summary is DynamicGridSumSummary sum)
+        {
+            var newSummary = new GridSummaryColumn
+            {
+                Format = $"{{Sum:{sum.Format}}}"
+            };
+            if(sum.AggregateType == typeof(double))
+            {
+                newSummary.SummaryType = Syncfusion.Data.SummaryType.DoubleAggregate;
+            }
+            else if(sum.AggregateType == typeof(int))
+            {
+                newSummary.SummaryType = Syncfusion.Data.SummaryType.Int32Aggregate;
+            }
+            else if(sum.AggregateType == typeof(TimeSpan))
+            {
+                newSummary.SummaryType = Syncfusion.Data.SummaryType.Custom;
+                newSummary.CustomAggregate = new DynamicGridDurationAggregate();
+            }
+            return newSummary;
+        }
+        else if(summary is DynamicGridCountSummary count)
+        {
+            return new GridSummaryColumn
+            {
+                Format = "{Count:N0}",
+                SummaryType = Syncfusion.Data.SummaryType.CountAggregate
+            };
+        }
+        else if(summary is DynamicGridCustomSummary custom)
+        {
+            return new GridSummaryColumn
+            {
+                Format = $"{{Sum:{custom.Format}}}",
+                SummaryType = SummaryType.Custom,
+                CustomAggregate = new InternalAggregate(this, custom.Aggregate)
+            };
+        }
+        else if(summary is DynamicGridTemplateSummary template)
+        {
+            return new GridSummaryColumn
+            {
+                TemplateSelector = new FuncTemplateSelector((item, o) => template.Template())
+            };
+        }
+        else
+        {
+            return null;
+        }
+    }
+
+    private class InternalAggregate(DynamicGridGridUIComponent<T> grid, DynamicGridCustomSummary.AggregateFunc aggregate) : ISummaryAggregate
+    {
+        private DynamicGridCustomSummary.AggregateFunc Aggregate = aggregate;
+
+        private DynamicGridGridUIComponent<T> Grid = grid;
+
+        public object? Sum { get; set; } = null;
+
+        public Action<IEnumerable, string, PropertyDescriptor> CalculateAggregateFunc() => CalculateAggregate;
+
+        private void CalculateAggregate(IEnumerable items, string property, PropertyDescriptor args)
+        {
+            if (items is IEnumerable<DataRowView> rows)
+            {
+                Sum = Aggregate(rows.Select(x =>
+                {
+                    var row = x.Row.Table.Rows.IndexOf(x.Row);
+                    return Grid.Parent.Data.Rows[row];
+                }));
+            }
+            else
+            {
+                Logger.Send(LogType.Error, "", $"Attempting to calculate aggregate on invalid data type '{items.GetType()}'.");
+            }
+        }
+    }
+
+    #endregion
+
     private void ApplyFilterStyle(GridColumn column, bool filtering, bool isactioncolumn)
     {
         var filterstyle = new Style();
@@ -1145,17 +1231,20 @@ public class DynamicGridGridUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
         {
             if (this.CreateEditorColumn(column, out var newcol, out var prop))
             {
-                newcol.GetEntity = () => _editingObject.Object;
+                newcol.GetEntity = () => _editingObject?.Object;
                 newcol.EntityChanged += DoEntityChanged;
                 if (!newcol.VariableHeight)
                     gridRowResizingOptions.ExcludeColumns.Add(newcol.MappingName);
 
                 var newColumn = newcol.CreateGridColumn();
 
-                var summary = newcol.Summary();
+                var summary = ConvertSummary(newcol.Summary());
                 if (summary != null)
+                {
+                    summary.Name = newcol.MappingName;
+                    summary.MappingName = newcol.MappingName;
                     Summaries.Add(summary);
-
+                }
                 
                 ApplyFilterStyle(newColumn, newcol.Filtered, false);
                 

+ 9 - 4
inabox.wpf/DynamicGrid/UIComponent/DynamicGridTreeUIComponent.cs

@@ -964,13 +964,11 @@ public class DynamicGridTreeUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
         {
             if(this.CreateEditorColumn(column, out var newcol, out var prop))
             {
-                //newcol.GetEntity = () => _editingObject.Object;
-                //newcol.EntityChanged += DoEntityChanged;
+                newcol.GetEntity = () => _editingObject?.Object;
+                newcol.EntityChanged += DoEntityChanged;
 
                 var newColumn = newcol.CreateTreeGridColumn();
 
-                //newColumn.AllowEditing = newcol.Editable && Parent.IsDirectEditMode();
-
                 ApplyFilterStyle(newColumn, newcol.Filtered, false);
                 
                 var headstyle = new Style(typeof(TreeGridHeaderCell));
@@ -1367,6 +1365,13 @@ public class DynamicGridTreeUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
         return _editingObject;
     }
 
+    private void DoEntityChanged(IDynamicColumnBase column, DynamicColumnEntityChangedEventArgs args)
+    {
+        if (_editingObject is null) return;
+
+        Parent.EntityChanged(_editingObject.Object, _editingObject.Row, args.ColumnName, args.Changes);
+    }
+
     private void UpdateData(string column, Dictionary<CoreColumn, object?> updates)
     {
         if (_editingObject is null)