浏览代码

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

frankvandenbos 8 月之前
父节点
当前提交
63f04a05eb

+ 19 - 9
InABox.Core/DataModel/AutoDataModel.cs

@@ -7,10 +7,21 @@ using System.Threading.Tasks;
 
 namespace InABox.Core
 {
-    public class AutoDataModel<T> : DataModel<T> where T : Entity, IPersistent, IRemotable, new()
+    internal static class _AutoDataModel
     {
         private static Type[]? _allo2mtypes;
 
+        public static Type[] GetOneOrManyToManyTypes()
+        {
+            _allo2mtypes ??= CoreUtils.Entities.Where(x => x.HasInterface(typeof(IOneToMany<>)) || x.HasInterface(typeof(IManyToMany<,>))).ToArray();
+            return _allo2mtypes;
+        }
+    }
+
+    public class AutoDataModel<T> : DataModel<T> where T : Entity, IPersistent, IRemotable, new()
+    {
+        private static bool _loaded = false;
+
         // Method; Parent Column; Child Column; Columns expression; Table Name
         private static readonly List<Tuple<MethodInfo, Expression, Expression, IColumns, string>> children =
             new List<Tuple<MethodInfo, Expression, Expression, IColumns, string>>();
@@ -47,14 +58,11 @@ namespace InABox.Core
 
             var headName = TableName<T>();
 
-            if (_allo2mtypes == null)
+            if (!_loaded)
             {
-                _allo2mtypes = CoreUtils.Entities.Where(x => x.HasInterface(typeof(IOneToMany<>)) || x.HasInterface(typeof(IManyToMany<,>))).ToArray();
-
-                var maps = _allo2mtypes.Where(x =>
-                        x.GetInterfaceDefinition(typeof(IOneToMany<>))?.GenericTypeArguments[0] == typeof(T)
-                        && !x.HasInterface<ISkipLoad>())
-                    .OrderBy(x => x.EntityName());
+                var maps = _AutoDataModel.GetOneOrManyToManyTypes()
+                    .Where(x => x.GetInterfaces(typeof(IOneToMany<>)).Any(x => x.GenericTypeArguments[0] == typeof(T)) && !x.HasInterface<ISkipLoad>())
+                    .OrderBy(x => x.Name);
                 var childMethod = GetType().GetMethods().Where(x => string.Equals(x.Name, nameof(AddChildTable)) && x.IsGenericMethod).FirstOrDefault();
                 var lookupMethod = GetType().GetMethods().Where(x => string.Equals(x.Name, nameof(AddLookupTable)) && x.IsGenericMethod).FirstOrDefault();
                 foreach (var map in maps)
@@ -104,7 +112,8 @@ namespace InABox.Core
                     }
                 }
 
-                var mapsLookup = _allo2mtypes.Where(x => x.GetInterfaceDefinition(typeof(IManyToMany<,>))?.GenericTypeArguments.Contains(typeof(T)) == true)
+                var mapsLookup = _AutoDataModel.GetOneOrManyToManyTypes()
+                    .Where(x => x.GetInterfaces(typeof(IManyToMany<,>)).Any(x => x.GenericTypeArguments.Contains(typeof(T))))
                     .OrderBy(x => x.EntityName());
                 foreach (var map in mapsLookup)
                 {
@@ -146,6 +155,7 @@ namespace InABox.Core
                         //_childtables.Add(new Tuple<Type, String, bool>(map, prop.Name, false));
                     }
                 }
+                _loaded = true;
             }
 
             foreach (var child in children)

+ 0 - 2
InABox.Core/Query/Column.cs

@@ -76,8 +76,6 @@ namespace InABox.Core
 
     public class Column<T> : IColumn
     {
-        private IProperty _property;
-
         public Type Type
         {
             get

+ 61 - 20
InABox.Core/Query/Filter.cs

@@ -4,6 +4,7 @@ using System.Collections.Generic;
 using System.Diagnostics.CodeAnalysis;
 using System.Linq;
 using System.Linq.Expressions;
+using System.Net.Sockets;
 using System.Reflection;
 using System.Runtime.Serialization;
 using Newtonsoft.Json;
@@ -399,6 +400,8 @@ namespace InABox.Core
 
         IEnumerable<IFilter> IFilter.Ors => Ors;
 
+        #region And
+
         public IFilter And<T1>(Expression<Func<T1, object>> expression)
         {
             return And(CoreUtils.GetFullPropertyName(expression, "."));
@@ -413,26 +416,6 @@ namespace InABox.Core
 
         IFilter IFilter.And(string property) => And(property);
 
-        public Filter<T> TextSearch(string terms, params Expression<Func<T, string>>[] expressions)
-        {
-            //String[] comps = terms.Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
-            //foreach (var comp in comps)
-            //{
-            //    Filter<T> search = null;
-            //    foreach (var expression in expressions)
-            //        search = search == null ? new Filter<T>(expression).Contains(comp.Trim()) : search.Or(expression).Contains(comp.Trim());
-            //    Ands.Add(search);
-            //}            
-            Filter<T>? search = null;
-            foreach (var expression in expressions)
-                search = search == null
-                    ? new Filter<T>(CoreUtils.GetFullPropertyName(expression, ".")).Contains(terms.Trim())
-                    : search.Or(CoreUtils.GetFullPropertyName(expression, ".")).Contains(terms.Trim());
-            if(search != null)
-                Ands.Add(search);
-            return this;
-        }
-
         public Filter<T> And(Filter<T> filter)
         {
             filter.Parent = this;
@@ -474,6 +457,30 @@ namespace InABox.Core
             return result;
         }
 
+        #endregion
+
+        public Filter<T> TextSearch(string terms, params Expression<Func<T, string>>[] expressions)
+        {
+            //String[] comps = terms.Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
+            //foreach (var comp in comps)
+            //{
+            //    Filter<T> search = null;
+            //    foreach (var expression in expressions)
+            //        search = search == null ? new Filter<T>(expression).Contains(comp.Trim()) : search.Or(expression).Contains(comp.Trim());
+            //    Ands.Add(search);
+            //}            
+            Filter<T>? search = null;
+            foreach (var expression in expressions)
+                search = search == null
+                    ? new Filter<T>(CoreUtils.GetFullPropertyName(expression, ".")).Contains(terms.Trim())
+                    : search.Or(CoreUtils.GetFullPropertyName(expression, ".")).Contains(terms.Trim());
+            if(search != null)
+                Ands.Add(search);
+            return this;
+        }
+
+        #region Or
+
         public IFilter Or<T1>(Expression<Func<T1, object>> expression)
         {
             return Or(CoreUtils.GetFullPropertyName(expression, "."));
@@ -509,6 +516,10 @@ namespace InABox.Core
             return or;
         }
 
+        #endregion
+
+        #region ApplyOperator
+
         private Filter<T> ApplyOperator<TValue>(Operator action, TValue value) where TValue : struct
         {
             Operator = action;
@@ -572,6 +583,8 @@ namespace InABox.Core
             return Parent ?? this;
         }
 
+        #endregion
+
         //public override void GetObjectData(SerializationInfo info, StreamingContext context)
         //{
         //	base.GetObjectData(info, context);
@@ -659,6 +672,34 @@ namespace InABox.Core
 
         #endregion
 
+        #region Casting
+
+        public Filter<TNew> Cast<TNew>()
+            where TNew : T
+        {
+            var prop = "";
+            if (CoreUtils.TryFindMemberExpression(Expression, out var mexp))
+            {
+                prop = CoreUtils.GetFullPropertyName(mexp, ".");
+            }
+
+            var filter = new Filter<TNew>(prop);
+            filter.Operator = Operator;
+            filter.Value = Value;
+            filter.IsNot = IsNot;
+            foreach(var and in Ands)
+            {
+                filter.And(and.Cast<TNew>());
+            }
+            foreach(var or in Ors)
+            {
+                filter.Or(or.Cast<TNew>());
+            }
+            return filter;
+        }
+
+        #endregion
+
         #region IsEqualTo
 
         public Filter<T> IsEqualTo(bool value) => ApplyOperator(Operator.IsEqualTo, value);

+ 3 - 3
inabox.database.sqlite/SQLiteProvider.cs

@@ -1354,7 +1354,7 @@ public class SQLiteProvider : IProvider
                 result = command.ExecuteNonQuery();
             }
         }
-        catch (Exception e)
+        catch
         {
             throw;
         }
@@ -3194,7 +3194,7 @@ public class SQLiteProvider : IProvider
                                                 ReadAndDecodeValue(result, reader, row, i);
                                             }
                                         }
-                                        catch (Exception e)
+                                        catch
                                         {
                                             row.Values.Add(result.Columns[i].DataType.GetDefault());
                                         }
@@ -3845,7 +3845,7 @@ public class SQLiteProvider : IProvider
         {
             return File.ReadAllBytes(filename);
         }
-        catch(Exception e)
+        catch
         {
             //Logger.Send(LogType.Error, "", $"Could not load external {T.Name}.{columnName}: {e.Message}");
             return null;

+ 3 - 19
inabox.wpf/DynamicGrid/UIComponent/DynamicGridGridUIComponent.cs

@@ -213,15 +213,9 @@ public class DynamicGridGridUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
         //DataGrid.CellRenderers.Add("TextBox", new CustomTextCellRenderer(this));
     }
 
-    public class GridSelectionControllerExt : GridSelectionController
+    public class GridSelectionControllerExt(SfDataGrid datagrid, DynamicGridGridUIComponent<T> grid) : GridSelectionController(datagrid)
     {
-        private DynamicGridGridUIComponent<T> Grid;
-
-        public GridSelectionControllerExt(SfDataGrid datagrid, DynamicGridGridUIComponent<T> grid)
-            : base(datagrid)
-        {
-            Grid = grid;
-        }
+        private DynamicGridGridUIComponent<T> Grid = grid;
 
         public override bool HandleKeyDown(KeyEventArgs args)
         {
@@ -1497,17 +1491,7 @@ public class DynamicGridGridUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
         var dataRow = GetDataRow(row);
         if(dataRow is not null)
         {
-            foreach(var (key, value) in row)
-            {
-                var datacolname = key.Replace(".", "_");
-                var dataValue = dataRow[datacolname];
-                if (!Equals(dataValue, value) && !(value is null && dataValue == DBNull.Value))
-                {
-                    dataRow[datacolname] = value ?? DBNull.Value;
-                }
-            }
-            for (var i = 0; i < ActionColumns.Count; i++)
-                dataRow[$"ActionColumn{i}"] = ActionColumns[i].Data(row);
+            UpdateRow(row, dataRow);
         }
     }
 

+ 131 - 77
inabox.wpf/DynamicGrid/UIComponent/DynamicGridTreeUIComponent.cs

@@ -247,6 +247,7 @@ public class DynamicGridTreeUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
         _tree.CurrentCellEndEdit += _tree_CurrentCellEndEdit;
         _tree.CurrentCellDropDownSelectionChanged += _tree_CurrentCellDropDownSelectionChanged;
         _tree.PreviewKeyUp += _tree_PreviewKeyUp;
+        _tree.SelectionController = new TreeGridSelectionControllerExt(_tree, this);
         
         _tree.ColumnSizer = TreeColumnSizer.None;
         _tree.RowHeight = 30D;
@@ -271,6 +272,24 @@ public class DynamicGridTreeUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
         _tree.SizeChanged += _tree_SizeChanged;
     }
 
+    private class TreeGridSelectionControllerExt(SfTreeGrid treeGrid, DynamicGridTreeUIComponent<T> grid) : TreeGridRowSelectionController(treeGrid)
+    {
+        private DynamicGridTreeUIComponent<T> Grid = grid;
+
+        public override bool HandleKeyDown(KeyEventArgs args)
+        {
+            if (args.Key == Key.Escape)
+            {
+                Grid.CancelEdit();
+                return false;
+            }
+            else
+            {
+                return base.HandleKeyDown(args);
+            }
+        }
+    }
+
     #region Public Interface
 
     public IEnumerable<CoreRow> GetChildren(Guid id)
@@ -394,6 +413,8 @@ public class DynamicGridTreeUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
 
     #endregion
 
+    #region FilterUI
+
     private void _tree_FilterItemsPopulating(object? sender, Syncfusion.UI.Xaml.TreeGrid.Filtering.TreeGridFilterItemsPopulatingEventArgs e)
     {
         var colIdx = _tree.Columns.IndexOf(e.Column);
@@ -477,21 +498,49 @@ public class DynamicGridTreeUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
         UpdateRecordCount();
     }
 
-    private CoreRow? GetRow(CoreTreeNode? node)
+    public void AddVisualFilter(string column, string value, FilterType filtertype = FilterType.Contains)
     {
-        return MapRow(node?.Row);
+        if (value.IsNullOrWhiteSpace())
+            return;
+        var col = _tree.Columns.FirstOrDefault((x => string.Equals(x.MappingName?.ToUpper(),column?.Replace(".", "_").ToUpper())));
+        if (col != null)
+        {
+            col.FilterPredicates.Add(new FilterPredicate { FilterType = filtertype, FilterValue = value });
+        }
     }
 
-    private CoreRow? MapRow(CoreRow? row)
+    public List<Tuple<string, Func<CoreRow, bool>>> GetFilterPredicates()
     {
-        if (row is null) return null;
-
-        var index = row.Index;
-        if (index < 0 || index >= Parent.Data.Rows.Count) return null;
-
-        return Parent.Data.Rows[row.Index];
+        var list = new List<Tuple<string, Func<CoreRow, bool>>>();
+        foreach (var column in _tree.Columns)
+        {
+            var colIndex = _tree.Columns.IndexOf(column);
+            var col = ColumnList[colIndex];
+            if (col is DynamicGridColumn gridColumn)
+            {
+                var rowPredicate = DynamicGridGridUIComponentExtension.ConvertColumnPredicates(gridColumn, column.FilterPredicates);
+                if(rowPredicate is not null)
+                {
+                    list.Add(new(gridColumn.ColumnName, rowPredicate));
+                }
+            }
+            else if(col is DynamicActionColumn dac && dac.FilterRecord is not null)
+            {
+                if(dac.SelectedFilters is not null && dac.SelectedFilters.Length > 0)
+                {
+                    list.Add(new(column.MappingName, (row) => dac.FilterRecord(row, dac.SelectedFilters)));
+                }
+                if(dac.ExcludeFilters is not null && dac.ExcludeFilters.Length > 0)
+                {
+                    list.Add(new(column.MappingName, (row) => !dac.FilterRecord(row, dac.ExcludeFilters)));
+                }
+            }
+        }
+        return list;
     }
 
+    #endregion
+
     private void ColumnsMenu_ContextMenuOpening(object sender, RoutedEventArgs e)
     {
         if (sender is not ContextMenu menu) return;
@@ -643,6 +692,39 @@ public class DynamicGridTreeUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
 
     #endregion
 
+    #region Rows
+
+    private CoreRow? GetRow(CoreTreeNode? node)
+    {
+        return MapRow(node?.Row);
+    }
+
+    private CoreRow? MapRow(CoreRow? row)
+    {
+        if (row is null) return null;
+
+        var index = row.Index;
+        if (index < 0 || index >= Parent.Data.Rows.Count) return null;
+
+        return Parent.Data.Rows[row.Index];
+    }
+
+    private CoreTreeNode? GetNode(CoreRow row)
+    {
+        if (_innerTable is null || row.Index < 0 || row.Index >= _innerTable.Rows.Count) return null;
+
+        var _innerRow = _innerTable.Rows[row.Index];
+        var node = Nodes.Find(_innerRow);
+        return node;
+    }
+
+    public CoreRow[] GetVisibleRows()
+    {
+        return _tree.View?.Nodes.Select(x => MapRow((x.Item as CoreTreeNode)?.Row)).NotNull().ToArray() ?? new CoreRow[] { };
+    }
+
+    #endregion
+
     #region Columns
 
     private class StackedHeaderRenderer : TreeGridStackedHeaderCellRenderer
@@ -1159,51 +1241,7 @@ public class DynamicGridTreeUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
 
     #endregion
 
-
-    public void AddVisualFilter(string column, string value, FilterType filtertype = FilterType.Contains)
-    {
-        if (value.IsNullOrWhiteSpace())
-            return;
-        var col = _tree.Columns.FirstOrDefault((x => string.Equals(x.MappingName?.ToUpper(),column?.Replace(".", "_").ToUpper())));
-        if (col != null)
-        {
-            col.FilterPredicates.Add(new FilterPredicate { FilterType = filtertype, FilterValue = value });
-        }
-    }
-    public List<Tuple<string, Func<CoreRow, bool>>> GetFilterPredicates()
-    {
-        var list = new List<Tuple<string, Func<CoreRow, bool>>>();
-        foreach (var column in _tree.Columns)
-        {
-            var colIndex = _tree.Columns.IndexOf(column);
-            var col = ColumnList[colIndex];
-            if (col is DynamicGridColumn gridColumn)
-            {
-                var rowPredicate = DynamicGridGridUIComponentExtension.ConvertColumnPredicates(gridColumn, column.FilterPredicates);
-                if(rowPredicate is not null)
-                {
-                    list.Add(new(gridColumn.ColumnName, rowPredicate));
-                }
-            }
-            else if(col is DynamicActionColumn dac && dac.FilterRecord is not null)
-            {
-                if(dac.SelectedFilters is not null && dac.SelectedFilters.Length > 0)
-                {
-                    list.Add(new(column.MappingName, (row) => dac.FilterRecord(row, dac.SelectedFilters)));
-                }
-                if(dac.ExcludeFilters is not null && dac.ExcludeFilters.Length > 0)
-                {
-                    list.Add(new(column.MappingName, (row) => !dac.FilterRecord(row, dac.ExcludeFilters)));
-                }
-            }
-        }
-        return list;
-    }
-
-    public CoreRow[] GetVisibleRows()
-    {
-        return _tree.View?.Nodes.Select(x => MapRow((x.Item as CoreTreeNode)?.Row)).NotNull().ToArray() ?? new CoreRow[] { };
-    }
+    #region Invalidation + Updating
 
     public void InvalidateRow(CoreRow row)
     {
@@ -1219,21 +1257,6 @@ public class DynamicGridTreeUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
         _invalidating = false;
     }
 
-
-    public void ScrollIntoView(CoreRow row)
-    {
-        _tree.ScrollInView(new RowColumnIndex(row.Index + 1, 0));
-    }
-
-    private CoreTreeNode? GetNode(CoreRow row)
-    {
-        if (_innerTable is null || row.Index < 0 || row.Index >= _innerTable.Rows.Count) return null;
-
-        var _innerRow = _innerTable.Rows[row.Index];
-        var node = Nodes.Find(_innerRow);
-        return node;
-    }
-
     public void UpdateCell(CoreRow row, string column, object? value)
     {
         var node = GetNode(row);
@@ -1243,9 +1266,9 @@ public class DynamicGridTreeUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
             node.InvalidateData();
         }
     }
+
     public void UpdateCell(CoreRow row, DynamicColumnBase column)
     {
-
         var node = GetNode(row);
         if(node is not null)
         {
@@ -1261,21 +1284,33 @@ public class DynamicGridTreeUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
         }
     }
 
+    public void UpdateRow(CoreRow row, CoreTreeNode dataRow)
+    {
+        foreach(var (key, value) in row)
+        {
+            dataRow[key] = value;
+        }
+        for (var i = 0; i < ActionColumns.Count; i++)
+            dataRow[$"_ActionColumn{i}"] = ActionColumns[i].Data(row);
+        dataRow.InvalidateData();
+    }
+
     public void UpdateRow(CoreRow row)
     {
         var dataRow = GetNode(row);
         if(dataRow is not null)
         {
-            foreach(var (key, value) in row)
-            {
-                dataRow[key] = value;
-            }
-            for (var i = 0; i < ActionColumns.Count; i++)
-                dataRow[$"_ActionColumn{i}"] = ActionColumns[i].Data(row);
-            dataRow.InvalidateData();
+            UpdateRow(row, dataRow);
         }
     }
 
+    #endregion
+
+    public void ScrollIntoView(CoreRow row)
+    {
+        _tree.ScrollInView(new RowColumnIndex(row.Index + 1, 0));
+    }
+
     #region Direct Edit
 
     private void _tree_PreviewKeyUp(object sender, KeyEventArgs e)
@@ -1297,6 +1332,13 @@ public class DynamicGridTreeUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
                 e.Handled = true;
             }
         }
+        else if(e.Key == Key.Escape)
+        {
+            if (Parent.IsDirectEditMode())
+            {
+                bChanged = false;
+            }
+        }
     }
 
     private bool bChanged;
@@ -1468,6 +1510,18 @@ public class DynamicGridTreeUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
         }
     }
 
+    private void CancelEdit()
+    {
+        var obj = _editingObject;
+        bChanged = false;
+        _editingObject = null;
+        _tree.SelectionController.CurrentCellManager.EndEdit(false);
+        if(obj is not null)
+        {
+            UpdateRow(obj.Row, obj.Node);
+        }
+    }
+
     private void _tree_CurrentCellEndEdit(object? sender, CurrentCellEndEditEventArgs e)
     {
         if (_editingObject is not null && bChanged)