Bladeren bron

Refactored DataTable.cs into individual class files
Renamed GlobalConfigurationSettings interface to IGlobalConfigurationSettings
Added Visual Filters to MultiSelectDialog

Frank van den Bos 2 jaren geleden
bovenliggende
commit
429ca4e026

+ 2 - 2
InABox.Configuration/GlobalConfiguration.cs

@@ -6,7 +6,7 @@ using InABox.Core;
 
 namespace InABox.Configuration
 {
-    public interface GlobalConfigurationSettings : IConfigurationSettings
+    public interface IGlobalConfigurationSettings : IConfigurationSettings
     {
     }
 
@@ -20,7 +20,7 @@ namespace InABox.Configuration
         public string Contents { get; set; }
     }
 
-    public class GlobalConfiguration<T> : Configuration<T> where T : GlobalConfigurationSettings, new()
+    public class GlobalConfiguration<T> : Configuration<T> where T : IGlobalConfigurationSettings, new()
     {
         public GlobalConfiguration(string section = "") : base(section)
         {

+ 0 - 92
InABox.Core/CoreDataTable.cs

@@ -1,92 +0,0 @@
-namespace InABox.Core
-{
-    //[Serializable]
-    //public class CoreTable<T> : DataTable, ICoreTable
-    //{
-    //    public CoreTable()
-    //        : base()
-    //    {
-    //    }
-
-    //    public CoreTable(string tableName)
-    //        : base(tableName)
-    //    {
-    //    }
-
-    //    public CoreTable(string tableName, string tableNamespace)
-    //        : base(tableName, tableNamespace)
-    //    {
-    //    }
-
-    //    public CoreTable(SerializationInfo info, StreamingContext context)
-    //        : base(info, context)
-    //    {
-    //    }
-
-    //    protected override Type GetRowType()
-    //    {
-    //        return typeof(CoreRow<T>);
-    //    }
-
-    //    protected override DataRow NewRowFromBuilder(DataRowBuilder builder)
-    //    {
-    //        return new CoreRow<T>(builder);
-    //    }
-    //}
-
-    //[Serializable]
-    //public class CoreRow<T> : DataRow, ICoreRow
-    //{
-
-    //    public CoreRow()
-    //        : base(null)
-    //    {
-    //    }
-
-    //    public CoreRow(DataRowBuilder builder)
-    //        : base(builder)
-    //    {
-    //    }
-
-    //    public int Index => throw new NotImplementedException();
-
-    //    public List<object> Values => throw new NotImplementedException();
-
-    //    public new CoreTable<T> Table { get; set; }
-
-    //    public TType Get<TType>(string columnname, bool usedefault = true)
-    //    {
-    //        throw new NotImplementedException();
-    //    }
-
-    //    public TType Get<TSource, TType>(Expression<Func<TSource, TType>> expression)
-    //    {
-    //        throw new NotImplementedException();
-    //    }
-
-    //    public void Set<TType>(string columnname, TType value)
-    //    {
-    //        throw new NotImplementedException();
-    //    }
-
-    //    public void Set<TSource, TType>(Expression<Func<TSource, TType>> expression, TType value)
-    //    {
-    //        throw new NotImplementedException();
-    //    }
-
-    //    public Dictionary<string, object> ToDictionary(string[] exclude)
-    //    {
-    //        throw new NotImplementedException();
-    //    }
-
-    //    public object ToObject(Type t)
-    //    {
-    //        throw new NotImplementedException();
-    //    }
-
-    //    public T1 ToObject<T1>() where T1 : BaseObject, new()
-    //    {
-    //        throw new NotImplementedException();
-    //    }
-    //}
-}

+ 31 - 0
InABox.Core/CoreTable/CoreColumn.cs

@@ -0,0 +1,31 @@
+using System;
+using System.Linq;
+
+namespace InABox.Core
+{
+    [Serializable]
+    public class CoreColumn
+    {
+        public CoreColumn()
+        {
+            DataType = typeof(object);
+        }
+        public CoreColumn(string columnName) : this(typeof(object), columnName) { }
+
+        public CoreColumn(Type dataType, string columnName)
+        {
+            DataType = dataType;
+            ColumnName = columnName;
+        }
+
+        public Type DataType { get; set; }
+
+        public string ColumnName { get; set; }
+
+        public override string ToString()
+        {
+            return string.Format("{0} ({1})", ColumnName, DataType.EntityName().Split('.').Last());
+        }
+
+    }
+}

+ 34 - 0
InABox.Core/CoreTable/CoreFieldMap.cs

@@ -0,0 +1,34 @@
+using System;
+using System.Collections.Generic;
+using System.Linq.Expressions;
+
+namespace InABox.Core
+{
+    
+    public class CoreFieldMapPair<T1, T2>
+    {
+            
+        public Expression<Func<T1, object>> From { get; private set; }
+        public Expression<Func<T2, object>> To { get; private set; }
+            
+        public CoreFieldMapPair(Expression<Func<T1, object>> from, Expression<Func<T2, object>> to)
+        {
+            From = from;
+            To = to;
+        }
+    }
+
+    
+    public class CoreFieldMap<T1, T2>
+    {
+        private List<CoreFieldMapPair<T1, T2>> _fields = new List<CoreFieldMapPair<T1, T2>>();
+
+        public CoreFieldMapPair<T1, T2>[] Fields => _fields.ToArray();
+        
+        public CoreFieldMap<T1, T2> Add(Expression<Func<T1, object>> from, Expression<Func<T2, object>> to)
+        {
+            _fields.Add(new CoreFieldMapPair<T1, T2>(from, to));
+            return this;
+        }
+    }
+}

+ 255 - 0
InABox.Core/CoreTable/CoreRow.cs

@@ -0,0 +1,255 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Linq.Expressions;
+
+namespace InABox.Core
+{
+    [Serializable]
+    public class CoreRow : ICoreRow
+    {
+        #region Fields
+
+        [NonSerialized]
+        private static Dictionary<int, string> _accessedcolumns = new Dictionary<int, string>();
+
+        [NonSerialized]
+        private Dictionary<string, int> _columnindexes = new Dictionary<string, int>();
+
+        #endregion
+
+        #region Properties
+
+        [DoNotSerialize]
+        [field: NonSerialized]
+        public CoreTable Table { get; private set; }
+        public List<object?> Values { get; private set; }
+
+        [DoNotSerialize]
+        public int Index => Table.Rows.IndexOf(this);
+
+        #endregion
+
+        protected internal CoreRow(CoreTable owner)
+        {
+            Table = owner;
+            Values = new List<object?>();
+        }
+
+        public static CoreRow[] None
+        {
+            get { return new CoreRow[] { }; }
+        }
+
+        //private DynamicObject rowObject;
+
+        public Dictionary<string, object?> ToDictionary(string[] exclude)
+        {
+            var result = new Dictionary<string, object?>();
+            foreach (var column in Table.Columns.Where(x => !exclude.Contains(x.ColumnName)))
+                result[column.ColumnName] = this[column.ColumnName];
+            return result;
+        }
+
+        [DoNotSerialize]
+        public object? this[string columnName]
+        {
+            get =>
+                //return this.RowObject.GetValue<object>(columnName);
+                Get<object>(columnName);
+            set =>
+                //this.RowObject.SetValue(columnName, value);
+                Set(columnName, value);
+        }
+
+        public BaseObject ToObject(Type t)
+        {
+            var entity = (Activator.CreateInstance(t) as BaseObject)!;
+            entity.SetObserving(false);
+
+            if (!Table.Setters.TryGetValue("", out var setters))
+            {
+                setters = new List<Action<object, object>?>();
+                Table.Setters[""] = setters;
+            }
+            
+            var bFirst = !setters.Any();
+
+            for (var i = 0; i < Table.Columns.Count; i++)
+            {
+                var column = Table.Columns[i].ColumnName;
+                var value = this[column];
+                try
+                {
+                    if (bFirst)
+                    {
+                        var prop = DatabaseSchema.Property(t, column);
+                        setters.Add(prop?.Setter());
+                    }
+
+                    var setter = setters[i];
+                    if (setter != null && value != null)
+                        setter.Invoke(entity, value);
+                    else
+                        CoreUtils.SetPropertyValue(entity, column, value);
+                }
+                catch (Exception e)
+                {
+                    Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
+                }
+            }
+
+            entity.CommitChanges();
+            entity.SetObserving(true);
+            return entity;
+        }
+
+        public T ToObject<T>() where T : BaseObject, new()
+        {
+            return (ToObject(typeof(T)) as T)!;
+        }
+
+        public T Get<T>(int col, bool usedefault = true)
+        {
+            if (col < 0 || col >= Values.Count)
+            {
+                if (usedefault)
+                    return CoreUtils.GetDefault<T>();
+                throw new Exception(string.Format("Column [{0}] does not exist!", col));
+            }
+
+            return Values[col] != null ? (T)CoreUtils.ChangeType(Values[col], typeof(T)) : CoreUtils.GetDefault<T>();
+
+        }
+        
+        public T Get<T>(string columnname, bool usedefault = true)
+        {
+            var col = GetColumn(columnname);
+
+            if (col < 0 || col >= Values.Count)
+            {
+                if (usedefault)
+                    return CoreUtils.GetDefault<T>();
+                throw new Exception(string.Format("Column [{0}] does not exist!", columnname));
+            }
+
+            return Values[col] != null ? (T)CoreUtils.ChangeType(Values[col], typeof(T)) : CoreUtils.GetDefault<T>();
+        }
+
+        public TType Get<TSource, TType>(Expression<Func<TSource, TType>> expression, bool usedefault = true)
+        {
+            var colname = GetColName(expression);
+            //String colname = CoreUtils.GetFullPropertyName(expression, ".");
+            return Get<TType>(colname, usedefault);
+        }
+
+        public void Set<TSource, TType>(Expression<Func<TSource, TType>> expression, TType value)
+        {
+            var colname = GetColName(expression);
+            //String colname = CoreUtils.GetFullPropertyName(expression, ".");
+            Set(colname, value);
+        }
+
+        public void Set<T>(int col, T value)
+        {
+            while (Values.Count <= col)
+                Values.Add(Table.Columns[Values.Count].DataType.GetDefault());
+
+            Values[col] = value;
+        }
+        
+        public void Set<T>(string columnname, T value)
+        {
+            var col = GetColumn(columnname);
+            if (col < 0)
+                throw new Exception("Column not found: " + columnname);
+
+            while (Values.Count <= col)
+                Values.Add(Table.Columns[Values.Count].DataType.GetDefault());
+
+            Values[col] = value;
+
+            //this.RowObject.SetValue(columnname, value);
+        }
+
+        public void LoadValues(IEnumerable<object?> values)
+        {
+            Values = values.ToList();
+        }
+
+        public T ToObject<TSource, TLink, T>(Expression<Func<TSource, TLink>> property)
+            where TLink : IEntityLink<T>
+            where T : BaseObject, new()
+        {
+            var entity = new T();
+            entity.SetObserving(false);
+
+            var prefix = CoreUtils.GetFullPropertyName(property, ".");
+            if (!Table.Setters.TryGetValue(prefix, out var setters))
+            {
+                setters = new List<Action<object, object>?>();
+                Table.Setters[prefix] = setters;
+            }
+            var bFirst = !setters.Any();
+
+            var cols = Table.Columns.Where(x => x.ColumnName.StartsWith(prefix + ".")).ToArray();
+
+            for (var i = 0; i < cols.Length; i++)
+            {
+                var column = cols[i].ColumnName;
+
+                var prop = column.Substring((prefix + ".").Length);
+                var value = this[column];
+                try
+                {
+                    if (bFirst)
+                    {
+                        var p2 = DatabaseSchema.Property(typeof(T), prop);
+                        setters.Add(p2?.Setter());
+                    }
+
+                    var setter = setters[i];
+                    if (setter != null && value != null)
+                        setter.Invoke(entity, value);
+                    else
+                        CoreUtils.SetPropertyValue(entity, prop, value);
+                }
+                catch (Exception e)
+                {
+                    Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
+                }
+            }
+
+            entity.CommitChanges();
+            entity.SetObserving(true);
+            return entity;
+        }
+
+        private string GetColName<TSource, TType>(Expression<Func<TSource, TType>> expression)
+        {
+            //int hash = expression.GetHashCode();
+            //if (_accessedcolumns.ContainsKey(hash))
+            //    return _accessedcolumns[hash];
+            var colname = CoreUtils.GetFullPropertyName(expression, ".");
+            //_accessedcolumns[hash] = colname;
+            return colname;
+        }
+
+        private int GetColumn(string columnname)
+        {
+            if (_columnindexes.ContainsKey(columnname))
+                return _columnindexes[columnname];
+
+            for (var i = 0; i < Table.Columns.Count; i++)
+                if (Table.Columns[i].ColumnName.Equals(columnname))
+                {
+                    _columnindexes[columnname] = i;
+                    return i;
+                }
+
+            _columnindexes[columnname] = -1;
+            return -1;
+        }
+
+    }
+}

+ 603 - 0
InABox.Core/CoreTable/CoreTable.cs

@@ -0,0 +1,603 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Data;
+using System.Linq;
+using System.Linq.Expressions;
+
+namespace InABox.Core
+{
+    [Serializable]
+    public class CoreTable : ICoreTable, ISerializeBinary //: IEnumerable, INotifyCollectionChanged
+    {
+
+        #region Fields
+
+        private List<CoreRow>? rows;
+        private List<CoreColumn> columns = new List<CoreColumn>();
+        private string tableName;
+
+        #endregion
+
+        #region Properties
+
+        public string TableName { get => tableName; }
+
+        public IList<CoreColumn> Columns { get => columns; }
+        public IList<CoreRow> Rows
+        {
+            get
+            {
+                rows ??= new List<CoreRow>();
+                //this.rows.CollectionChanged += OnRowsCollectionChanged;
+                return rows;
+            }
+        }
+
+        [field: NonSerialized]
+        public Dictionary<string, IList<Action<object, object>?>> Setters { get; } = new Dictionary<string, IList<Action<object, object>?>>();
+
+        #endregion
+
+        public CoreTable() : this("")
+        {
+        }
+
+        public CoreTable(string tableName): base()
+        {
+            this.tableName = tableName;
+        }
+
+        public CoreTable(Type type) : this()
+        {
+            LoadColumns(type);
+        }
+        
+        public void AddColumn<T>(Expression<Func<T, object>> column)
+        {
+            Columns.Add(
+                new CoreColumn()
+                {
+                    ColumnName = CoreUtils.GetFullPropertyName(column, "."),
+                    DataType = column.ReturnType
+                }
+            );
+        }
+        
+        public CoreRow NewRow(bool populate = false)
+        {
+            var result = new CoreRow(this);
+            if (populate)
+                foreach (var column in Columns)
+                    result[column.ColumnName] = column.DataType.GetDefault();
+            return result;
+        }
+
+        /*
+        private void OnRowsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
+        {
+            switch (e.Action)
+            {
+                case NotifyCollectionChangedAction.Add:
+                    this.InternalView.Insert(e.NewStartingIndex, ((DataRow)e.NewItems[0]).RowObject);
+                    break;
+                case NotifyCollectionChangedAction.Remove:
+                    this.InternalView.RemoveAt(e.OldStartingIndex);
+                    break;
+                case NotifyCollectionChangedAction.Replace:
+                    this.InternalView.Remove(((DataRow)e.OldItems[0]).RowObject);
+                    this.InternalView.Insert(e.NewStartingIndex, ((DataRow)e.NewItems[0]).RowObject);
+                    break;
+                case NotifyCollectionChangedAction.Reset:
+                default:
+                    this.InternalView.Clear();
+                    this.Rows.Select(r => r.RowObject).ToList().ForEach(o => this.InternalView.Add(o));
+                    break;
+            }
+        }
+        
+        private IList InternalView
+        {
+            get
+            {
+                if (this.internalView == null)
+                {
+                    this.CreateInternalView();
+                }
+
+                return this.internalView;
+            }
+        }
+
+        private void CreateInternalView()
+        {
+            this.internalView = (IList)Activator.CreateInstance(typeof(ObservableCollection<>).MakeGenericType(this.ElementType));
+            ((INotifyCollectionChanged)internalView).CollectionChanged += (s, e) => { this.OnCollectionChanged(e); };
+        }
+
+        internal Type ElementType
+        {
+            get
+            {
+                if (this.elementType == null)
+                {
+                    this.InitializeElementType();
+                }
+
+                return this.elementType;
+            }
+        }
+
+        private void InitializeElementType()
+        {
+            this.Seal();
+            this.elementType = DynamicObjectBuilder.GetDynamicObjectBuilderType(this.Columns);
+        }
+
+        private void Seal()
+        {
+            this.columns = new ReadOnlyCollection<DataColumn>(this.Columns);
+        }
+
+        public IEnumerator GetEnumerator()
+        {
+            return this.InternalView.GetEnumerator();
+        }
+
+        public IList ToList()
+        {
+            return this.InternalView;
+        }
+
+        protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
+        {
+            var handler = this.CollectionChanged;
+            if (handler != null)
+            {
+                handler(this, e);
+            }
+        }
+        */
+
+        public void LoadColumns(Type T)
+        {
+            var iprops = DatabaseSchema.Properties(T);
+            foreach (var iprop in iprops)
+                Columns.Add(new CoreColumn { ColumnName = iprop.Name, DataType = iprop.PropertyType });
+        }
+        
+        public void LoadColumns(IColumns columns)
+        {
+            foreach (var col in columns.GetColumns())
+                Columns.Add(new CoreColumn { ColumnName = col.Property, DataType = col.Type });
+        }
+        
+        public void LoadColumns(IEnumerable<CoreColumn> columns)
+        {
+            Columns.Clear();
+            foreach (var col in columns)
+                Columns.Add(new CoreColumn() { ColumnName = col.ColumnName, DataType = col.DataType }); 
+        }
+
+        public void LoadRows(IEnumerable<object> objects)
+        {
+            foreach (var obj in objects)
+            {
+                var row = NewRow();
+                LoadRow(row, obj);
+                Rows.Add(row);
+            }
+        }
+
+        public void LoadRows(CoreRow[] rows)
+        {
+            foreach (var row in rows)
+            {
+                var newrow = NewRow();
+                LoadRow(newrow, row);
+                Rows.Add(newrow);
+            }
+        }
+
+        public void LoadFrom<T1, T2>(CoreTable table, CoreFieldMap<T1, T2> mappings, Action<CoreRow>? customization = null)
+        {
+            foreach (var row in table.Rows)
+            {
+                var newrow = NewRow();
+                foreach (var map in mappings.Fields)
+                    newrow.Set(map.To, row.Get(map.From));
+                customization?.Invoke(newrow);
+                Rows.Add(newrow);
+            }
+        }
+
+        public void LoadRow(CoreRow row, object obj)
+        {
+            foreach (var col in Columns)
+                try
+                {
+                    //var prop = DataModel.Property(obj.GetType(), col.ColumnName);
+                    //if (prop is CustomProperty)
+                    //    prop is CustomProperty ? item.UserProperties[key] : CoreUtils.GetPropertyValue(item, key);
+                    var fieldvalue = CoreUtils.GetPropertyValue(obj, col.ColumnName);
+                    row[col.ColumnName] = fieldvalue;
+                }
+                catch (Exception e)
+                {
+                    Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
+                }
+        }
+
+        public void LoadRow(CoreRow row, CoreRow from)
+        {
+            foreach (var col in Columns)
+                try
+                {
+                    if (from.Table.Columns.Any(x => x.ColumnName.Equals(col.ColumnName)))
+                        row[col.ColumnName] = from[col.ColumnName];
+                }
+                catch (Exception e)
+                {
+                    Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
+                }
+        }
+
+        public void Filter(Func<CoreRow, bool> predicate)
+        {
+            for (var i = Rows.Count - 1; i > -1; i--)
+            {
+                var row = Rows[i];
+                var predresult = predicate.Invoke(row);
+                if (!predresult)
+                    Rows.Remove(row);
+            }
+        }
+        
+        #region ToDictionary
+
+        public IDictionary ToDictionary(string keycol, string displaycol, string sortcol = "")
+        {
+            var kc = Columns.FirstOrDefault(x => x.ColumnName.Equals(keycol));
+            var dc = Columns.FirstOrDefault(x => x.ColumnName.Equals(displaycol));
+            var dt = typeof(Dictionary<,>).MakeGenericType(kc.DataType, dc.DataType);
+            var id = (Activator.CreateInstance(dt) as IDictionary)!;
+            var sorted = string.IsNullOrWhiteSpace(sortcol) ? Rows : Rows.OrderBy(x => x.Get<object>(sortcol)).ToList();
+            foreach (var row in sorted)
+                id[row[keycol]] = row[displaycol];
+            return id;
+        }
+
+        public Dictionary<TKey, TValue> ToDictionary<T, TKey, TValue>(Expression<Func<T, TKey>> key, Expression<Func<T, TValue>> value,
+            Expression<Func<T, object>>? sort = null)
+        {
+            var result = new Dictionary<TKey, TValue>();
+            var sorted = sort == null ? Rows : Rows.OrderBy(x => x.Get(sort)).ToList();
+            foreach (var row in Rows)
+                result[row.Get(key)] = row.Get(value);
+            return result;
+        }
+
+        public Dictionary<TKey, string> ToDictionary<T, TKey>(Expression<Func<T, TKey>> key, Expression<Func<T, object>>[] values,
+            Expression<Func<T, object>>? sort = null)
+        {
+            var result = new Dictionary<TKey, string>();
+            var sorted = sort == null ? Rows : Rows.OrderBy(x => x.Get(sort)).ToList();
+            foreach (var row in Rows)
+            {
+                var display = new List<object>();
+                foreach (var value in values)
+                    display.Add(row.Get(value));
+                result[row.Get(key)] = string.Join(" : ", display);
+            }
+
+            return result;
+        }
+
+        public Dictionary<TKey, TValue> ToDictionary<T, TKey, TValue>(Expression<Func<T, TKey>> key, Func<CoreRow, TValue> value,
+            Expression<Func<T, object>>? sort = null)
+        {
+            var result = new Dictionary<TKey, TValue>();
+            var sorted = sort == null ? Rows : Rows.OrderBy(x => x.Get(sort)).ToList();
+            foreach (var row in Rows)
+                result[row.Get(key)] = value(row);
+            return result;
+        }
+
+        public void LoadDictionary<T, TKey, TValue>(Dictionary<TKey, TValue> dictionary, Expression<Func<T, TKey>> key,
+            Expression<Func<T, TValue>> value)
+        {
+            foreach (var row in Rows) 
+                dictionary[row.Get(key)] = row.Get(value);
+        }
+        
+        public Dictionary<TKey, string> IntoDictionary<T, TKey>(Dictionary<TKey, string> result, Expression<Func<T, TKey>> key,
+            params Expression<Func<T, object>>[] values)
+        {
+            foreach (var row in Rows)
+            {
+                var display = new List<object>();
+                foreach (var value in values)
+                    display.Add(row.Get(value));
+                result[row.Get(key)] = string.Join(" : ", display);
+            }
+
+            return result;
+        }
+
+        public Dictionary<TKey, TValue> IntoDictionary<T, TKey, TValue>(Dictionary<TKey, TValue> result, Expression<Func<T, TKey>> key,
+            Func<CoreRow, TValue> value)
+        {
+            foreach (var row in Rows)
+                result[row.Get(key)] = value(row);
+            return result;
+        }
+        
+        #endregion
+
+        public DataTable ToDataTable(string name = "", IColumns? additionalColumns = null)
+        {
+            var result = new DataTable(name);
+            foreach (var column in Columns)
+                result.Columns.Add(column.ColumnName.Replace('.', '_'), column.DataType);
+            if(additionalColumns != null)
+            {
+                foreach (var (column, type) in additionalColumns.AsDictionary())
+                    result.Columns.Add(column.Replace('.', '_'), type);
+            }
+
+            //result.Columns["ID"].Unique = true;
+            //result.PrimaryKey = new DataColumn[] { result.Columns["ID"] };
+
+            foreach (var row in Rows)
+            {
+                //result.Rows.Add(row.Values.ToArray());
+                var newrow = result.NewRow();
+                newrow.ItemArray = row.Values.ToArray();
+                result.Rows.Add(newrow);
+            }
+
+            return result;
+        }
+        
+        #region ToObjects
+
+        public IEnumerable<BaseObject> ToObjects(Type T)
+            => Rows.Select(x => x.ToObject(T));
+        public IEnumerable<T> ToObjects<T>() where T : BaseObject, new()
+            => Rows.Select(x => x.ToObject<T>());
+        
+        #endregion
+        
+        #region ToTuples
+        
+        
+        public IEnumerable<Tuple<T1, T2>> ToTuples<TType, T1, T2>(
+            Expression<Func<TType, T1>> item1, 
+            Expression<Func<TType, T2>> item2
+            )
+        {
+            return Rows.Select(row =>
+                new Tuple<T1, T2>
+                (
+                    row.Get<TType,T1>(item1),
+                    row.Get<TType,T2>(item2)
+                )
+            );
+        }
+        
+        public IEnumerable<Tuple<T1, T2, T3>> ToTuples<TType, T1, T2, T3>(
+            Expression<Func<TType, T1>> item1, 
+            Expression<Func<TType, T2>> item2, 
+            Expression<Func<TType, T3>> item3)
+        {
+            return Rows.Select(row =>
+                new Tuple<T1, T2, T3>
+                (
+                    row.Get<TType,T1>(item1),
+                    row.Get<TType,T2>(item2),
+                    row.Get<TType,T3>(item3)
+                )
+            );
+        }
+        
+        public IEnumerable<Tuple<T1, T2, T3, T4>> ToTuples<TType, T1, T2, T3, T4>(
+            Expression<Func<TType, T1>> item1, 
+            Expression<Func<TType, T2>> item2, 
+            Expression<Func<TType, T3>> item3,
+            Expression<Func<TType, T4>> item4
+            )
+        {
+            return Rows.Select(row =>
+                new Tuple<T1, T2, T3, T4>
+                (
+                    row.Get<TType,T1>(item1),
+                    row.Get<TType,T2>(item2),
+                    row.Get<TType,T3>(item3),
+                    row.Get<TType,T4>(item4)
+                )
+            );
+        }
+        
+        public IEnumerable<Tuple<T1, T2, T3, T4, T5>> ToTuples<TType, T1, T2, T3, T4, T5>(
+            Expression<Func<TType, T1>> item1, 
+            Expression<Func<TType, T2>> item2, 
+            Expression<Func<TType, T3>> item3,
+            Expression<Func<TType, T4>> item4,
+            Expression<Func<TType, T5>> item5
+
+        )
+        {
+            return Rows.Select(row =>
+                new Tuple<T1, T2, T3, T4,T5>
+                (
+                    row.Get<TType,T1>(item1),
+                    row.Get<TType,T2>(item2),
+                    row.Get<TType,T3>(item3),
+                    row.Get<TType,T4>(item4),
+                    row.Get<TType,T5>(item5)
+                )
+            );
+        }
+        
+        #endregion
+
+        public void CopyTo(DataTable table)
+        {
+            var columns = new List<string>();
+            foreach (var column in Columns)
+                columns.Add(column.ColumnName.Replace('.', '_'));
+
+            foreach (var row in Rows)
+            {
+                var newrow = table.NewRow();
+                for (var i = 0; i < columns.Count; i++)
+                    newrow[columns[i]] = row.Values[i];
+                table.Rows.Add(newrow);
+            }
+        }
+
+        public void CopyTo(CoreTable table)
+        {
+            var columns = new List<string>();
+            //foreach (var column in Columns)
+            //    columns.Add(column.ColumnName.Replace('.', '_'));
+
+            foreach (var row in Rows)
+            {
+                var newrow = table.NewRow();
+                foreach (var column in Columns)
+                    if (table.Columns.Any(x => x.ColumnName.Equals(column.ColumnName)))
+                        newrow[column.ColumnName] = row[column.ColumnName];
+                //for (int i = 0; i < columns.Count; i++)
+                //    newrow.Set(columns[i], row.Values[i]);
+                table.Rows.Add(newrow);
+            }
+        }
+
+        #region Extract Values
+        
+        public IEnumerable<TValue> ExtractValues<TSource, TValue>(Expression<Func<TSource, TValue>> column, bool distinct = true)
+        {
+            var result = Rows.Select(r => r.Get(column));
+            if (distinct)
+                result = result.Distinct();
+            return result;
+        }
+
+        public IEnumerable<TValue> ExtractValues<TValue>(string column, bool distinct = true)
+        {
+            var result = Rows.Select(r => r.Get<TValue>(column));
+            if (distinct)
+                result = result.Distinct();
+            return result;
+        }
+
+        #endregion
+
+        public CoreTable LoadRow(object obj)
+        {
+            var row = NewRow();
+            LoadRow(row, obj);
+            Rows.Add(row);
+            return this;
+        }
+
+        #region ToLookup
+
+        public IMutableLookup<TKey, TValue> ToLookup<T, TKey, TValue>(Expression<Func<T, TKey>> key, Expression<Func<T, TValue>> value,
+            Expression<Func<T, object>>? sort = null)
+        {
+            IMutableLookup<TKey, TValue> result = new MutableLookup<TKey, TValue>(
+                Rows.ToLookup(
+                    r => r.Get(key),
+                    r => r.Get(value)
+                )
+            );
+            return result;
+        }
+
+        public IMutableLookup<TKey, TValue> ToLookup<T, TKey, TValue>(Expression<Func<T, TKey>> key, Func<CoreRow, TValue> value,
+            Expression<Func<T, object>>? sort = null)
+        {
+            IMutableLookup<TKey, TValue> result = new MutableLookup<TKey, TValue>(
+                Rows.ToLookup(
+                    r => r.Get(key),
+                    r => value(r)
+                )
+            );
+            return result;
+        }
+        
+        #endregion
+
+        #region Serialize Binary
+
+        public void WriteBinary(CoreBinaryWriter writer, bool includeColumns)
+        {
+            writer.Write(TableName);
+
+            if (includeColumns)
+            {
+                foreach (var column in Columns)
+                {
+                    writer.Write(true);
+                    writer.Write(column.ColumnName);
+                    writer.Write(column.DataType.EntityName());
+                }
+                writer.Write(false);
+            }
+
+            writer.Write(Rows.Count);
+            foreach (var row in Rows)
+            {
+                foreach (var col in Columns)
+                {
+                    var val = row[col.ColumnName];
+                    writer.WriteBinaryValue(col.DataType, val);
+                }
+            }
+        }
+
+        public void SerializeBinary(CoreBinaryWriter writer) => WriteBinary(writer, true);
+
+        public void ReadBinary(CoreBinaryReader reader, IList<CoreColumn>? columns)
+        {
+            tableName = reader.ReadString();
+
+            Columns.Clear();
+            if (columns is null)
+            {
+                while (reader.ReadBoolean())
+                {
+                    var columnName = reader.ReadString();
+                    var dataType = CoreUtils.GetEntity(reader.ReadString());
+                    Columns.Add(new CoreColumn(dataType, columnName));
+                }
+            }
+            else
+            {
+                foreach (var column in columns)
+                {
+                    Columns.Add(column);
+                }
+            }
+
+            Rows.Clear();
+            var nRows = reader.ReadInt32();
+            for (int i = 0; i < nRows; ++i)
+            {
+                var row = NewRow();
+                foreach (var column in Columns)
+                {
+                    var value = reader.ReadBinaryValue(column.DataType);
+                    row.Values.Add(value);
+                }
+                Rows.Add(row);
+            }
+        }
+
+        public void DeserializeBinary(CoreBinaryReader reader) => ReadBinary(reader, null);
+
+        #endregion
+    }
+}

+ 41 - 0
InABox.Core/CoreTable/CoreTableAdapter.cs

@@ -0,0 +1,41 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace InABox.Core
+{
+    public class CoreTableAdapter<T> : IEnumerable<T> where T : BaseObject, new()
+    {
+        private List<T>? _objects;
+
+        private readonly CoreTable _table;
+
+        public CoreTableAdapter(CoreTable table)
+        {
+            _table = table;
+        }
+
+        private List<T> Objects
+        {
+            get => _objects ??= _table.Rows.Select(row => row.ToObject<T>()).ToList();
+        }
+
+        public T this[int index] => Objects[index];
+
+
+        public IEnumerator<T> GetEnumerator()
+        {
+            return GetObjects();
+        }
+
+        IEnumerator IEnumerable.GetEnumerator()
+        {
+            return GetObjects();
+        }
+
+        private IEnumerator<T> GetObjects()
+        {
+            return Objects.GetEnumerator();
+        }
+    }
+}

+ 149 - 0
InABox.Core/CoreTable/CoreTableJsonConverter.cs

@@ -0,0 +1,149 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Drawing;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+
+namespace InABox.Core
+{
+
+    public class CoreTableJsonConverter : JsonConverter
+    {
+        public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
+        {
+            if(!(value is CoreTable table))
+            {
+                writer.WriteNull();
+                return;
+            }
+
+            writer.WriteStartObject();
+            writer.WritePropertyName("Columns");
+            var cols = new Dictionary<string, string>();
+            foreach (var column in table.Columns)
+                cols[column.ColumnName] = column.DataType.EntityName();
+            serializer.Serialize(writer, cols);
+            //writer.WriteEndObject();
+
+            //writer.WriteStartObject();
+            writer.WritePropertyName("Rows");
+            writer.WriteStartArray();
+            var size = 0;
+            foreach (var row in table.Rows)
+                //Console.WriteLine("- Serializing Row #"+row.Index.ToString());
+                try
+                {
+                    writer.WriteStartArray();
+                    foreach (var col in table.Columns)
+                    {
+                        var val = row[col.ColumnName];
+                        if (val != null) size += val.ToString().Length;
+                        //Console.WriteLine(String.Format("Serializing Row #{0} Column [{1}] Length={2}", row.Index.ToString(), col.ColumnName, val.ToString().Length));
+                        if (col.DataType.IsArray && val != null)
+                        {
+                            writer.WriteStartArray();
+                            foreach (var val1 in (Array)val)
+                                writer.WriteValue(val1);
+                            writer.WriteEndArray();
+                        }
+                        else if (col.DataType.GetInterfaces().Contains(typeof(IPackableList)))
+                        {
+                            writer.WriteStartArray();
+                            foreach (var val1 in (IList)val)
+                                writer.WriteValue(val1);
+                            writer.WriteEndArray();
+                        }
+                        else
+                        {
+                            writer.WriteValue(val ?? CoreUtils.GetDefault(col.DataType));
+                        }
+                    }
+
+                    writer.WriteEndArray();
+                    //Console.WriteLine(String.Format("[{0:D8}] Serializing Row #{1}", size, row.Index.ToString()));
+                }
+                catch (Exception e)
+                {
+                    Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
+                }
+
+            writer.WriteEndArray();
+            writer.WriteEndObject();
+        }
+
+        public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
+        {
+            if (reader.TokenType == JsonToken.Null)
+                return null;
+
+            var result = new CoreTable();
+            try
+            {
+                var json = JObject.Load(reader);
+                if (json.TryGetValue("Columns", out var columns))
+                {
+                    foreach (JProperty column in columns.Children())
+                    {
+                        var name = column.Name;
+                        var type = column.Value.ToObject<string>();
+                        result.Columns.Add(new CoreColumn { ColumnName = name, DataType = CoreUtils.GetEntity(type ?? "") });
+                    }
+                }
+
+                if (json.TryGetValue("Rows", out var rows))
+                {
+                    foreach (JArray row in rows.Children())
+                        if (row.Children().ToArray().Length == result.Columns.Count)
+                        {
+                            var newrow = result.NewRow();
+                            var iCol = 0;
+                            foreach (var cell in row.Children())
+                            {
+                                var column = result.Columns[iCol];
+                                try
+                                {
+                                    if (column.DataType.IsArray)
+                                    {
+                                        newrow[column.ColumnName] = cell.ToObject(column.DataType);
+                                    }
+                                    else if (column.DataType.GetInterfaces().Contains(typeof(IPackableList)))
+                                    {
+                                    }
+                                    else
+                                    {
+                                        newrow[column.ColumnName] = cell.ToObject(column.DataType);
+                                    }
+       
+                                }
+                                catch (Exception e)
+                                {
+                                    Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
+                                }
+
+                                iCol++;
+                            }
+
+                            result.Rows.Add(newrow);
+                        }
+                }
+            }
+            catch (Exception e)
+            {
+                Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
+            }
+
+            return result;
+            
+        }
+
+
+        public override bool CanConvert(Type objectType)
+        {
+            return typeof(CoreTable).GetTypeInfo().IsAssignableFrom(objectType);
+        }
+    }
+}

+ 0 - 1051
InABox.Core/DataTable.cs

@@ -1,1051 +0,0 @@
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Data;
-using System.Drawing;
-using System.IO;
-using System.Linq;
-using System.Linq.Expressions;
-using System.Reflection;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
-
-namespace InABox.Core
-{
-    // Equivalent to DataColumn
-
-    [Serializable]
-    public class CoreColumn
-    {
-        public CoreColumn()
-        {
-            DataType = typeof(object);
-        }
-        public CoreColumn(string columnName) : this(typeof(object), columnName) { }
-
-        public CoreColumn(Type dataType, string columnName)
-        {
-            DataType = dataType;
-            ColumnName = columnName;
-        }
-
-        public Type DataType { get; set; }
-
-        public string ColumnName { get; set; }
-
-        public override string ToString()
-        {
-            return string.Format("{0} ({1})", ColumnName, DataType.EntityName().Split('.').Last());
-        }
-
-    }
-
-    [Serializable]
-    public class CoreRow : ICoreRow
-    {
-        #region Fields
-
-        [NonSerialized]
-        private static Dictionary<int, string> _accessedcolumns = new Dictionary<int, string>();
-
-        [NonSerialized]
-        private Dictionary<string, int> _columnindexes = new Dictionary<string, int>();
-
-        #endregion
-
-        #region Properties
-
-        [DoNotSerialize]
-        [field: NonSerialized]
-        public CoreTable Table { get; private set; }
-        public List<object?> Values { get; private set; }
-
-        [DoNotSerialize]
-        public int Index => Table.Rows.IndexOf(this);
-
-        #endregion
-
-        protected internal CoreRow(CoreTable owner)
-        {
-            Table = owner;
-            Values = new List<object?>();
-        }
-
-        public static CoreRow[] None
-        {
-            get { return new CoreRow[] { }; }
-        }
-
-        //private DynamicObject rowObject;
-
-        public Dictionary<string, object?> ToDictionary(string[] exclude)
-        {
-            var result = new Dictionary<string, object?>();
-            foreach (var column in Table.Columns.Where(x => !exclude.Contains(x.ColumnName)))
-                result[column.ColumnName] = this[column.ColumnName];
-            return result;
-        }
-
-        [DoNotSerialize]
-        public object? this[string columnName]
-        {
-            get =>
-                //return this.RowObject.GetValue<object>(columnName);
-                Get<object>(columnName);
-            set =>
-                //this.RowObject.SetValue(columnName, value);
-                Set(columnName, value);
-        }
-
-        public BaseObject ToObject(Type t)
-        {
-            var entity = (Activator.CreateInstance(t) as BaseObject)!;
-            entity.SetObserving(false);
-
-            if (!Table.Setters.TryGetValue("", out var setters))
-            {
-                setters = new List<Action<object, object>?>();
-                Table.Setters[""] = setters;
-            }
-            
-            var bFirst = !setters.Any();
-
-            for (var i = 0; i < Table.Columns.Count; i++)
-            {
-                var column = Table.Columns[i].ColumnName;
-                var value = this[column];
-                try
-                {
-                    if (bFirst)
-                    {
-                        var prop = DatabaseSchema.Property(t, column);
-                        setters.Add(prop?.Setter());
-                    }
-
-                    var setter = setters[i];
-                    if (setter != null && value != null)
-                        setter.Invoke(entity, value);
-                    else
-                        CoreUtils.SetPropertyValue(entity, column, value);
-                }
-                catch (Exception e)
-                {
-                    Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
-                }
-            }
-
-            entity.CommitChanges();
-            entity.SetObserving(true);
-            return entity;
-        }
-
-        public T ToObject<T>() where T : BaseObject, new()
-        {
-            return (ToObject(typeof(T)) as T)!;
-        }
-
-        public T Get<T>(int col, bool usedefault = true)
-        {
-            if (col < 0 || col >= Values.Count)
-            {
-                if (usedefault)
-                    return CoreUtils.GetDefault<T>();
-                throw new Exception(string.Format("Column [{0}] does not exist!", col));
-            }
-
-            return Values[col] != null ? (T)CoreUtils.ChangeType(Values[col], typeof(T)) : CoreUtils.GetDefault<T>();
-
-        }
-        
-        public T Get<T>(string columnname, bool usedefault = true)
-        {
-            var col = GetColumn(columnname);
-
-            if (col < 0 || col >= Values.Count)
-            {
-                if (usedefault)
-                    return CoreUtils.GetDefault<T>();
-                throw new Exception(string.Format("Column [{0}] does not exist!", columnname));
-            }
-
-            return Values[col] != null ? (T)CoreUtils.ChangeType(Values[col], typeof(T)) : CoreUtils.GetDefault<T>();
-        }
-
-        public TType Get<TSource, TType>(Expression<Func<TSource, TType>> expression, bool usedefault = true)
-        {
-            var colname = GetColName(expression);
-            //String colname = CoreUtils.GetFullPropertyName(expression, ".");
-            return Get<TType>(colname, usedefault);
-        }
-
-        public void Set<TSource, TType>(Expression<Func<TSource, TType>> expression, TType value)
-        {
-            var colname = GetColName(expression);
-            //String colname = CoreUtils.GetFullPropertyName(expression, ".");
-            Set(colname, value);
-        }
-
-        public void Set<T>(int col, T value)
-        {
-            while (Values.Count <= col)
-                Values.Add(Table.Columns[Values.Count].DataType.GetDefault());
-
-            Values[col] = value;
-        }
-        
-        public void Set<T>(string columnname, T value)
-        {
-            var col = GetColumn(columnname);
-            if (col < 0)
-                throw new Exception("Column not found: " + columnname);
-
-            while (Values.Count <= col)
-                Values.Add(Table.Columns[Values.Count].DataType.GetDefault());
-
-            Values[col] = value;
-
-            //this.RowObject.SetValue(columnname, value);
-        }
-
-        public void LoadValues(IEnumerable<object?> values)
-        {
-            Values = values.ToList();
-        }
-
-        public T ToObject<TSource, TLink, T>(Expression<Func<TSource, TLink>> property)
-            where TLink : IEntityLink<T>
-            where T : BaseObject, new()
-        {
-            var entity = new T();
-            entity.SetObserving(false);
-
-            var prefix = CoreUtils.GetFullPropertyName(property, ".");
-            if (!Table.Setters.TryGetValue(prefix, out var setters))
-            {
-                setters = new List<Action<object, object>?>();
-                Table.Setters[prefix] = setters;
-            }
-            var bFirst = !setters.Any();
-
-            var cols = Table.Columns.Where(x => x.ColumnName.StartsWith(prefix + ".")).ToArray();
-
-            for (var i = 0; i < cols.Length; i++)
-            {
-                var column = cols[i].ColumnName;
-
-                var prop = column.Substring((prefix + ".").Length);
-                var value = this[column];
-                try
-                {
-                    if (bFirst)
-                    {
-                        var p2 = DatabaseSchema.Property(typeof(T), prop);
-                        setters.Add(p2?.Setter());
-                    }
-
-                    var setter = setters[i];
-                    if (setter != null && value != null)
-                        setter.Invoke(entity, value);
-                    else
-                        CoreUtils.SetPropertyValue(entity, prop, value);
-                }
-                catch (Exception e)
-                {
-                    Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
-                }
-            }
-
-            entity.CommitChanges();
-            entity.SetObserving(true);
-            return entity;
-        }
-
-        private string GetColName<TSource, TType>(Expression<Func<TSource, TType>> expression)
-        {
-            //int hash = expression.GetHashCode();
-            //if (_accessedcolumns.ContainsKey(hash))
-            //    return _accessedcolumns[hash];
-            var colname = CoreUtils.GetFullPropertyName(expression, ".");
-            //_accessedcolumns[hash] = colname;
-            return colname;
-        }
-
-        private int GetColumn(string columnname)
-        {
-            if (_columnindexes.ContainsKey(columnname))
-                return _columnindexes[columnname];
-
-            for (var i = 0; i < Table.Columns.Count; i++)
-                if (Table.Columns[i].ColumnName.Equals(columnname))
-                {
-                    _columnindexes[columnname] = i;
-                    return i;
-                }
-
-            _columnindexes[columnname] = -1;
-            return -1;
-        }
-
-    }
-
-    public class CoreFieldMap<T1, T2>
-    {
-        private List<CoreFieldMapPair<T1, T2>> _fields = new List<CoreFieldMapPair<T1, T2>>();
-
-        public CoreFieldMapPair<T1, T2>[] Fields => _fields.ToArray();
-        
-        public CoreFieldMap<T1, T2> Add(Expression<Func<T1, object>> from, Expression<Func<T2, object>> to)
-        {
-            _fields.Add(new CoreFieldMapPair<T1, T2>(from, to));
-            return this;
-        }
-    }
-    
-    public class CoreFieldMapPair<T1, T2>
-    {
-            
-        public Expression<Func<T1, object>> From { get; private set; }
-        public Expression<Func<T2, object>> To { get; private set; }
-            
-        public CoreFieldMapPair(Expression<Func<T1, object>> from, Expression<Func<T2, object>> to)
-        {
-            From = from;
-            To = to;
-        }
-    }
-
-    [Serializable]
-    public class CoreTable : ICoreTable, ISerializeBinary //: IEnumerable, INotifyCollectionChanged
-    {
-
-        #region Fields
-
-        private List<CoreRow>? rows;
-        private List<CoreColumn> columns = new List<CoreColumn>();
-        private string tableName;
-
-        #endregion
-
-        #region Properties
-
-        public string TableName { get => tableName; }
-
-        public IList<CoreColumn> Columns { get => columns; }
-        public IList<CoreRow> Rows
-        {
-            get
-            {
-                rows ??= new List<CoreRow>();
-                //this.rows.CollectionChanged += OnRowsCollectionChanged;
-                return rows;
-            }
-        }
-
-        [field: NonSerialized]
-        public Dictionary<string, IList<Action<object, object>?>> Setters { get; } = new Dictionary<string, IList<Action<object, object>?>>();
-
-        #endregion
-
-        public CoreTable() : this("")
-        {
-        }
-
-        public CoreTable(string tableName): base()
-        {
-            this.tableName = tableName;
-        }
-
-        public CoreTable(Type type) : this()
-        {
-            LoadColumns(type);
-        }
-        
-        public void AddColumn<T>(Expression<Func<T, object>> column)
-        {
-            Columns.Add(
-                new CoreColumn()
-                {
-                    ColumnName = CoreUtils.GetFullPropertyName(column, "."),
-                    DataType = column.ReturnType
-                }
-            );
-        }
-        
-        public CoreRow NewRow(bool populate = false)
-        {
-            var result = new CoreRow(this);
-            if (populate)
-                foreach (var column in Columns)
-                    result[column.ColumnName] = column.DataType.GetDefault();
-            return result;
-        }
-
-        /*
-        private void OnRowsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
-        {
-            switch (e.Action)
-            {
-                case NotifyCollectionChangedAction.Add:
-                    this.InternalView.Insert(e.NewStartingIndex, ((DataRow)e.NewItems[0]).RowObject);
-                    break;
-                case NotifyCollectionChangedAction.Remove:
-                    this.InternalView.RemoveAt(e.OldStartingIndex);
-                    break;
-                case NotifyCollectionChangedAction.Replace:
-                    this.InternalView.Remove(((DataRow)e.OldItems[0]).RowObject);
-                    this.InternalView.Insert(e.NewStartingIndex, ((DataRow)e.NewItems[0]).RowObject);
-                    break;
-                case NotifyCollectionChangedAction.Reset:
-                default:
-                    this.InternalView.Clear();
-                    this.Rows.Select(r => r.RowObject).ToList().ForEach(o => this.InternalView.Add(o));
-                    break;
-            }
-        }
-        
-        private IList InternalView
-        {
-            get
-            {
-                if (this.internalView == null)
-                {
-                    this.CreateInternalView();
-                }
-
-                return this.internalView;
-            }
-        }
-
-        private void CreateInternalView()
-        {
-            this.internalView = (IList)Activator.CreateInstance(typeof(ObservableCollection<>).MakeGenericType(this.ElementType));
-            ((INotifyCollectionChanged)internalView).CollectionChanged += (s, e) => { this.OnCollectionChanged(e); };
-        }
-
-        internal Type ElementType
-        {
-            get
-            {
-                if (this.elementType == null)
-                {
-                    this.InitializeElementType();
-                }
-
-                return this.elementType;
-            }
-        }
-
-        private void InitializeElementType()
-        {
-            this.Seal();
-            this.elementType = DynamicObjectBuilder.GetDynamicObjectBuilderType(this.Columns);
-        }
-
-        private void Seal()
-        {
-            this.columns = new ReadOnlyCollection<DataColumn>(this.Columns);
-        }
-
-        public IEnumerator GetEnumerator()
-        {
-            return this.InternalView.GetEnumerator();
-        }
-
-        public IList ToList()
-        {
-            return this.InternalView;
-        }
-
-        protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
-        {
-            var handler = this.CollectionChanged;
-            if (handler != null)
-            {
-                handler(this, e);
-            }
-        }
-        */
-
-        public void LoadColumns(Type T)
-        {
-            var iprops = DatabaseSchema.Properties(T);
-            foreach (var iprop in iprops)
-                Columns.Add(new CoreColumn { ColumnName = iprop.Name, DataType = iprop.PropertyType });
-        }
-        
-        public void LoadColumns(IColumns columns)
-        {
-            foreach (var col in columns.GetColumns())
-                Columns.Add(new CoreColumn { ColumnName = col.Property, DataType = col.Type });
-        }
-        
-        public void LoadColumns(IEnumerable<CoreColumn> columns)
-        {
-            Columns.Clear();
-            foreach (var col in columns)
-                Columns.Add(new CoreColumn() { ColumnName = col.ColumnName, DataType = col.DataType }); 
-        }
-
-        public void LoadRows(IEnumerable<object> objects)
-        {
-            foreach (var obj in objects)
-            {
-                var row = NewRow();
-                LoadRow(row, obj);
-                Rows.Add(row);
-            }
-        }
-
-        public void LoadRows(CoreRow[] rows)
-        {
-            foreach (var row in rows)
-            {
-                var newrow = NewRow();
-                LoadRow(newrow, row);
-                Rows.Add(newrow);
-            }
-        }
-
-        public void LoadFrom<T1, T2>(CoreTable table, CoreFieldMap<T1, T2> mappings, Action<CoreRow>? customization = null)
-        {
-            foreach (var row in table.Rows)
-            {
-                var newrow = NewRow();
-                foreach (var map in mappings.Fields)
-                    newrow.Set(map.To, row.Get(map.From));
-                customization?.Invoke(newrow);
-                Rows.Add(newrow);
-            }
-        }
-
-        public void LoadRow(CoreRow row, object obj)
-        {
-            foreach (var col in Columns)
-                try
-                {
-                    //var prop = DataModel.Property(obj.GetType(), col.ColumnName);
-                    //if (prop is CustomProperty)
-                    //    prop is CustomProperty ? item.UserProperties[key] : CoreUtils.GetPropertyValue(item, key);
-                    var fieldvalue = CoreUtils.GetPropertyValue(obj, col.ColumnName);
-                    row[col.ColumnName] = fieldvalue;
-                }
-                catch (Exception e)
-                {
-                    Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
-                }
-        }
-
-        public void LoadRow(CoreRow row, CoreRow from)
-        {
-            foreach (var col in Columns)
-                try
-                {
-                    if (from.Table.Columns.Any(x => x.ColumnName.Equals(col.ColumnName)))
-                        row[col.ColumnName] = from[col.ColumnName];
-                }
-                catch (Exception e)
-                {
-                    Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
-                }
-        }
-
-        public void Filter(Func<CoreRow, bool> predicate)
-        {
-            for (var i = Rows.Count - 1; i > -1; i--)
-            {
-                var row = Rows[i];
-                var predresult = predicate.Invoke(row);
-                if (!predresult)
-                    Rows.Remove(row);
-            }
-        }
-
-        public IDictionary ToDictionary(string keycol, string displaycol, string sortcol = "")
-        {
-            var kc = Columns.FirstOrDefault(x => x.ColumnName.Equals(keycol));
-            var dc = Columns.FirstOrDefault(x => x.ColumnName.Equals(displaycol));
-            var dt = typeof(Dictionary<,>).MakeGenericType(kc.DataType, dc.DataType);
-            var id = (Activator.CreateInstance(dt) as IDictionary)!;
-            var sorted = string.IsNullOrWhiteSpace(sortcol) ? Rows : Rows.OrderBy(x => x.Get<object>(sortcol)).ToList();
-            foreach (var row in sorted)
-                id[row[keycol]] = row[displaycol];
-            return id;
-        }
-
-        public Dictionary<TKey, TValue> ToDictionary<T, TKey, TValue>(Expression<Func<T, TKey>> key, Expression<Func<T, TValue>> value,
-            Expression<Func<T, object>>? sort = null)
-        {
-            var result = new Dictionary<TKey, TValue>();
-            var sorted = sort == null ? Rows : Rows.OrderBy(x => x.Get(sort)).ToList();
-            foreach (var row in Rows)
-                result[row.Get(key)] = row.Get(value);
-            return result;
-        }
-
-        public Dictionary<TKey, string> ToDictionary<T, TKey>(Expression<Func<T, TKey>> key, Expression<Func<T, object>>[] values,
-            Expression<Func<T, object>>? sort = null)
-        {
-            var result = new Dictionary<TKey, string>();
-            var sorted = sort == null ? Rows : Rows.OrderBy(x => x.Get(sort)).ToList();
-            foreach (var row in Rows)
-            {
-                var display = new List<object>();
-                foreach (var value in values)
-                    display.Add(row.Get(value));
-                result[row.Get(key)] = string.Join(" : ", display);
-            }
-
-            return result;
-        }
-
-        public Dictionary<TKey, TValue> ToDictionary<T, TKey, TValue>(Expression<Func<T, TKey>> key, Func<CoreRow, TValue> value,
-            Expression<Func<T, object>>? sort = null)
-        {
-            var result = new Dictionary<TKey, TValue>();
-            var sorted = sort == null ? Rows : Rows.OrderBy(x => x.Get(sort)).ToList();
-            foreach (var row in Rows)
-                result[row.Get(key)] = value(row);
-            return result;
-        }
-
-        public void LoadDictionary<T, TKey, TValue>(Dictionary<TKey, TValue> dictionary, Expression<Func<T, TKey>> key,
-            Expression<Func<T, TValue>> value)
-        {
-            foreach (var row in Rows) dictionary[row.Get(key)] = row.Get(value);
-        }
-
-        public DataTable ToDataTable(string name = "", IColumns? additionalColumns = null)
-        {
-            var result = new DataTable(name);
-            foreach (var column in Columns)
-                result.Columns.Add(column.ColumnName.Replace('.', '_'), column.DataType);
-            if(additionalColumns != null)
-            {
-                foreach (var (column, type) in additionalColumns.AsDictionary())
-                    result.Columns.Add(column.Replace('.', '_'), type);
-            }
-
-            //result.Columns["ID"].Unique = true;
-            //result.PrimaryKey = new DataColumn[] { result.Columns["ID"] };
-
-            foreach (var row in Rows)
-            {
-                //result.Rows.Add(row.Values.ToArray());
-                var newrow = result.NewRow();
-                newrow.ItemArray = row.Values.ToArray();
-                result.Rows.Add(newrow);
-            }
-
-            return result;
-        }
-
-        public IEnumerable<BaseObject> ToObjects(Type T)
-            => Rows.Select(x => x.ToObject(T));
-        public IEnumerable<T> ToObjects<T>() where T : BaseObject, new()
-            => Rows.Select(x => x.ToObject<T>());
-        public List<T> ToList<T>() where T : BaseObject, new()
-            => ToObjects<T>().ToList();
-
-        public void CopyTo(DataTable table)
-        {
-            var columns = new List<string>();
-            foreach (var column in Columns)
-                columns.Add(column.ColumnName.Replace('.', '_'));
-
-            foreach (var row in Rows)
-            {
-                var newrow = table.NewRow();
-                for (var i = 0; i < columns.Count; i++)
-                    newrow[columns[i]] = row.Values[i];
-                table.Rows.Add(newrow);
-            }
-        }
-
-        public void CopyTo(CoreTable table)
-        {
-            var columns = new List<string>();
-            //foreach (var column in Columns)
-            //    columns.Add(column.ColumnName.Replace('.', '_'));
-
-            foreach (var row in Rows)
-            {
-                var newrow = table.NewRow();
-                foreach (var column in Columns)
-                    if (table.Columns.Any(x => x.ColumnName.Equals(column.ColumnName)))
-                        newrow[column.ColumnName] = row[column.ColumnName];
-                //for (int i = 0; i < columns.Count; i++)
-                //    newrow.Set(columns[i], row.Values[i]);
-                table.Rows.Add(newrow);
-            }
-        }
-
-        public IEnumerable<TValue> ExtractValues<TSource, TValue>(Expression<Func<TSource, TValue>> column, bool distinct = true)
-        {
-            var result = Rows.Select(r => r.Get(column));
-            if (distinct)
-                result = result.Distinct();
-            return result;
-        }
-
-        public IEnumerable<TValue> ExtractValues<TValue>(string column, bool distinct = true)
-        {
-            var result = Rows.Select(r => r.Get<TValue>(column));
-            if (distinct)
-                result = result.Distinct();
-            return result;
-        }
-
-
-
-        public CoreTable LoadRow(object obj)
-        {
-            var row = NewRow();
-            LoadRow(row, obj);
-            Rows.Add(row);
-            return this;
-        }
-
-        public Dictionary<TKey, string> IntoDictionary<T, TKey>(Dictionary<TKey, string> result, Expression<Func<T, TKey>> key,
-            params Expression<Func<T, object>>[] values)
-        {
-            foreach (var row in Rows)
-            {
-                var display = new List<object>();
-                foreach (var value in values)
-                    display.Add(row.Get(value));
-                result[row.Get(key)] = string.Join(" : ", display);
-            }
-
-            return result;
-        }
-
-        public Dictionary<TKey, TValue> IntoDictionary<T, TKey, TValue>(Dictionary<TKey, TValue> result, Expression<Func<T, TKey>> key,
-            Func<CoreRow, TValue> value)
-        {
-            foreach (var row in Rows)
-                result[row.Get(key)] = value(row);
-            return result;
-        }
-
-        public IMutableLookup<TKey, TValue> ToLookup<T, TKey, TValue>(Expression<Func<T, TKey>> key, Expression<Func<T, TValue>> value,
-            Expression<Func<T, object>>? sort = null)
-        {
-            IMutableLookup<TKey, TValue> result = new MutableLookup<TKey, TValue>(
-                Rows.ToLookup(
-                    r => r.Get(key),
-                    r => r.Get(value)
-                )
-            );
-            return result;
-        }
-
-        public IMutableLookup<TKey, TValue> ToLookup<T, TKey, TValue>(Expression<Func<T, TKey>> key, Func<CoreRow, TValue> value,
-            Expression<Func<T, object>>? sort = null)
-        {
-            IMutableLookup<TKey, TValue> result = new MutableLookup<TKey, TValue>(
-                Rows.ToLookup(
-                    r => r.Get(key),
-                    r => value(r)
-                )
-            );
-            return result;
-        }
-
-        #region Serialize Binary
-
-        public void WriteBinary(CoreBinaryWriter writer, bool includeColumns)
-        {
-            writer.Write(TableName);
-
-            if (includeColumns)
-            {
-                foreach (var column in Columns)
-                {
-                    writer.Write(true);
-                    writer.Write(column.ColumnName);
-                    writer.Write(column.DataType.EntityName());
-                }
-                writer.Write(false);
-            }
-
-            writer.Write(Rows.Count);
-            foreach (var row in Rows)
-            {
-                foreach (var col in Columns)
-                {
-                    var val = row[col.ColumnName];
-                    writer.WriteBinaryValue(col.DataType, val);
-                }
-            }
-        }
-
-        public void SerializeBinary(CoreBinaryWriter writer) => WriteBinary(writer, true);
-
-        public void ReadBinary(CoreBinaryReader reader, IList<CoreColumn>? columns)
-        {
-            tableName = reader.ReadString();
-
-            Columns.Clear();
-            if (columns is null)
-            {
-                while (reader.ReadBoolean())
-                {
-                    var columnName = reader.ReadString();
-                    var dataType = CoreUtils.GetEntity(reader.ReadString());
-                    Columns.Add(new CoreColumn(dataType, columnName));
-                }
-            }
-            else
-            {
-                foreach (var column in columns)
-                {
-                    Columns.Add(column);
-                }
-            }
-
-            Rows.Clear();
-            var nRows = reader.ReadInt32();
-            for (int i = 0; i < nRows; ++i)
-            {
-                var row = NewRow();
-                foreach (var column in Columns)
-                {
-                    var value = reader.ReadBinaryValue(column.DataType);
-                    row.Values.Add(value);
-                }
-                Rows.Add(row);
-            }
-        }
-
-        public void DeserializeBinary(CoreBinaryReader reader) => ReadBinary(reader, null);
-
-        #endregion
-    }
-
-    public class CoreTableAdapter<T> : IEnumerable<T> where T : BaseObject, new()
-    {
-        private List<T>? _objects;
-
-        private readonly CoreTable _table;
-
-        public CoreTableAdapter(CoreTable table)
-        {
-            _table = table;
-        }
-
-        private List<T> Objects
-        {
-            get => _objects ??= _table.Rows.Select(row => row.ToObject<T>()).ToList();
-        }
-
-        public T this[int index] => Objects[index];
-
-
-        public IEnumerator<T> GetEnumerator()
-        {
-            return GetObjects();
-        }
-
-        IEnumerator IEnumerable.GetEnumerator()
-        {
-            return GetObjects();
-        }
-
-        private IEnumerator<T> GetObjects()
-        {
-            return Objects.GetEnumerator();
-        }
-    }
-
-    public class DataTableJsonConverter : JsonConverter
-    {
-        public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
-        {
-            if(!(value is CoreTable table))
-            {
-                writer.WriteNull();
-                return;
-            }
-
-            writer.WriteStartObject();
-            writer.WritePropertyName("Columns");
-            var cols = new Dictionary<string, string>();
-            foreach (var column in table.Columns)
-                cols[column.ColumnName] = column.DataType.EntityName();
-            serializer.Serialize(writer, cols);
-            //writer.WriteEndObject();
-
-            //writer.WriteStartObject();
-            writer.WritePropertyName("Rows");
-            writer.WriteStartArray();
-            var size = 0;
-            foreach (var row in table.Rows)
-                //Console.WriteLine("- Serializing Row #"+row.Index.ToString());
-                try
-                {
-                    writer.WriteStartArray();
-                    foreach (var col in table.Columns)
-                    {
-                        var val = row[col.ColumnName];
-                        if (val != null) size += val.ToString().Length;
-                        //Console.WriteLine(String.Format("Serializing Row #{0} Column [{1}] Length={2}", row.Index.ToString(), col.ColumnName, val.ToString().Length));
-                        if (col.DataType.IsArray && val != null)
-                        {
-                            writer.WriteStartArray();
-                            foreach (var val1 in (Array)val)
-                                writer.WriteValue(val1);
-                            writer.WriteEndArray();
-                        }
-                        else if (col.DataType.GetInterfaces().Contains(typeof(IPackableList)))
-                        {
-                            writer.WriteStartArray();
-                            foreach (var val1 in (IList)val)
-                                writer.WriteValue(val1);
-                            writer.WriteEndArray();
-                        }
-                        else
-                        {
-                            writer.WriteValue(val ?? CoreUtils.GetDefault(col.DataType));
-                        }
-                    }
-
-                    writer.WriteEndArray();
-                    //Console.WriteLine(String.Format("[{0:D8}] Serializing Row #{1}", size, row.Index.ToString()));
-                }
-                catch (Exception e)
-                {
-                    Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
-                }
-
-            writer.WriteEndArray();
-            writer.WriteEndObject();
-        }
-
-        public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
-        {
-            if (reader.TokenType == JsonToken.Null)
-                return null;
-
-            var result = new CoreTable();
-            try
-            {
-                var json = JObject.Load(reader);
-                if (json.TryGetValue("Columns", out var columns))
-                {
-                    foreach (JProperty column in columns.Children())
-                    {
-                        var name = column.Name;
-                        var type = column.Value.ToObject<string>();
-                        result.Columns.Add(new CoreColumn { ColumnName = name, DataType = CoreUtils.GetEntity(type ?? "") });
-                    }
-                }
-
-                if (json.TryGetValue("Rows", out var rows))
-                {
-                    foreach (JArray row in rows.Children())
-                        if (row.Children().ToArray().Length == result.Columns.Count)
-                        {
-                            var newrow = result.NewRow();
-                            var iCol = 0;
-                            foreach (var cell in row.Children())
-                            {
-                                var column = result.Columns[iCol];
-                                try
-                                {
-                                    if (column.DataType.IsArray)
-                                    {
-                                        newrow[column.ColumnName] = cell.ToObject(column.DataType);
-                                    }
-                                    else if (column.DataType.GetInterfaces().Contains(typeof(IPackableList)))
-                                    {
-                                    }
-                                    else
-                                    {
-                                        newrow[column.ColumnName] = cell.ToObject(column.DataType);
-                                    }
-                                    //if ((column.DataType == typeof(byte[])) && (value != null))
-                                    //    newrow[column.ColumnName] = Convert.FromBase64String(value.ToString());
-                                    //else if (cell is JValue)
-                                    //    value = ((JValue)cell).Value;
-                                    //else if (cell is JObject)
-                                    //    value = ((JObject)cell).ToObject(column.DataType);
-                                    //else if (cell is JArray)
-                                    //    value = ((JArray)cell).ToObject(column.DataType);
-                                    //else
-                                    //    value = null;
-                                }
-                                catch (Exception e)
-                                {
-                                    Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
-                                }
-
-                                iCol++;
-                            }
-
-                            result.Rows.Add(newrow);
-                        }
-                }
-            }
-            catch (Exception e)
-            {
-                Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
-            }
-
-            return result;
-
-            //String json = reader.Value.ToString();
-
-            //var table = new CoreTable();
-
-            //Dictionary<String, Object> dict = Serialization.Deserialize<Dictionary<String, Object>>(json);
-
-            //Dictionary<String, String> columns = Serialization.Deserialize<Dictionary<String, String>>(dict["Columns"].ToString());
-            //List<List<Object>> rows = Serialization.Deserialize<List<List<Object>>>(dict["Rows"].ToString());
-
-            //String[] keys = columns.Keys.ToArray();
-
-            //foreach (String key in keys)
-            //    table.Columns.Add(new CoreColumn() { ColumnName = key, DataType = CoreUtils.GetEntity(columns[key]) });
-
-
-            //foreach (List<Object> row in rows)
-            //{
-            //    CoreRow newrow = table.NewRow();
-            //    for (int i = 0; i < keys.Count(); i++)
-            //    {
-            //        if (row[i] is JObject)
-            //            newrow[keys[i]] = JsonConvert.DeserializeObject(row[i].ToString(), table.Columns[i].DataType);
-            //        else if (table.Columns[i].DataType == typeof(byte[]))
-            //        {
-            //            if (row[i] != null)
-            //                newrow.Set(keys[i], Convert.FromBase64String(row[i].ToString()));
-            //        }
-            //        else
-            //        {
-            //            try
-            //            {
-            //                object o = row[i];
-            //                if (table.Columns[i].DataType != null)
-            //                    o = CoreUtils.ChangeType(o, table.Columns[i].DataType);
-            //                newrow.Set(keys[i], o);
-            //            }
-            //            catch (Exception e)
-            //            {
-
-            //            }
-            //        }
-            //        //newrow[keys[i]] = row[i];
-            //    }
-            //    table.Rows.Add(newrow);
-            //}
-
-            //return table;
-        }
-
-
-        public override bool CanConvert(Type objectType)
-        {
-            return typeof(CoreTable).GetTypeInfo().IsAssignableFrom(objectType);
-        }
-    }
-}

+ 1 - 2
InABox.Core/ICoreTable.cs

@@ -29,8 +29,7 @@ namespace InABox.Core
         IDictionary ToDictionary(string keycol, string displaycol, string sortcol = "");
 
         IEnumerable<T> ToObjects<T>() where T : BaseObject, new();
-        List<T> ToList<T>() where T : BaseObject, new();
-
+        
         Dictionary<TKey, TValue> ToDictionary<T, TKey, TValue>(Expression<Func<T, TKey>> key, Expression<Func<T, TValue>> value,
             Expression<Func<T, object>>? sort = null);
 

+ 1 - 1
InABox.Core/Serialization.cs

@@ -37,7 +37,7 @@ namespace InABox.Core
                     DateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind
                 };
 
-                _serializerSettings.Converters.Add(new DataTableJsonConverter());
+                _serializerSettings.Converters.Add(new CoreTableJsonConverter());
                 //serializerSettings.Converters.Add(new DateTimeJsonConverter());
 
                 _serializerSettings.Converters.Add(new FilterJsonConverter());

+ 1 - 1
InABox.Database/DataUpdater.cs

@@ -12,7 +12,7 @@ using System.Threading.Tasks;
 namespace InABox.Database
 {
 
-    public class DatabaseVersion : BaseObject, GlobalConfigurationSettings
+    public class DatabaseVersion : BaseObject, IGlobalConfigurationSettings
     {
         public string Version { get; set; }
 

+ 2 - 2
InABox.Serialization.Json/JsonSerializer.cs

@@ -15,7 +15,7 @@ namespace InABox.Serialization
                 DateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind
             };
 
-            serializerSettings.Converters.Add(new DataTableJsonConverter());
+            serializerSettings.Converters.Add(new CoreTableJsonConverter());
             //serializerSettings.Converters.Add(new DateTimeJsonConverter());
 
             serializerSettings.Converters.Add(new FilterJsonConverter());
@@ -54,7 +54,7 @@ namespace InABox.Serialization
                 DateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind
             };
 
-            serializerSettings.Converters.Add(new DataTableJsonConverter());
+            serializerSettings.Converters.Add(new CoreTableJsonConverter());
             //serializerSettings.Converters.Add(new DateTimeJsonConverter());
 
             serializerSettings.Converters.Add(new FilterJsonConverter());

+ 1 - 1
inabox.wpf/DynamicGrid/DynamicGridColumns.cs

@@ -7,7 +7,7 @@ using InABox.Core;
 
 namespace InABox.DynamicGrid
 {
-    public class DynamicGridColumns : List<DynamicGridColumn>, GlobalConfigurationSettings, UserConfigurationSettings
+    public class DynamicGridColumns : List<DynamicGridColumn>, IGlobalConfigurationSettings, UserConfigurationSettings
 
     {
         public string GridName { get; set; }

+ 1 - 1
inabox.wpf/DynamicGrid/DynamicGridFilter.cs

@@ -19,5 +19,5 @@ namespace InABox.DynamicGrid
         public string Filter { get; set; }
     }
 
-    public class DynamicGridFilters : List<DynamicGridFilter>, GlobalConfigurationSettings { }
+    public class DynamicGridFilters : List<DynamicGridFilter>, IGlobalConfigurationSettings { }
 }

+ 5 - 2
inabox.wpf/DynamicGrid/MultiSelectDialog.cs

@@ -1,6 +1,7 @@
 using System;
 using System.ComponentModel;
 using System.Linq;
+using System.Linq.Expressions;
 using System.Windows;
 using System.Windows.Controls;
 using InABox.Clients;
@@ -11,7 +12,7 @@ namespace InABox.DynamicGrid
 {
     public interface IMultiSelectDialog
     {
-        bool ShowDialog();
+        bool ShowDialog(String? column = null, String? filter = null);
         Guid[] IDs();
         CoreTable Data();
     }
@@ -96,11 +97,13 @@ namespace InABox.DynamicGrid
             grid.Children.Add(CancelButton);
         }
 
-        public bool ShowDialog()
+        public bool ShowDialog(String? column = null, String? value = null)
         {
             window = new ThemableWindow { Title = "Select Items", WindowStyle = WindowStyle.SingleBorderWindow };
             window.Content = grid;
             datagrid.Refresh(true, true);
+            if (!String.IsNullOrEmpty(column) && !String.IsNullOrEmpty(value))
+                datagrid.AddVisualFilter(column, value);
             if (window.ShowDialog() == true)
                 return true;
             return false;

+ 1 - 1
inabox.wpf/DynamicGrid/ScreenLayout.cs

@@ -2,7 +2,7 @@
 
 namespace InABox.DynamicGrid
 {
-    internal class ScreenLayout : GlobalConfigurationSettings
+    internal class ScreenLayout : IGlobalConfigurationSettings
     {
         public string XAML { get; set; }
     }