Browse Source

Fixed tab strip height on DynamicTabControl; added question image to MessageWindow

Kenric Nugteren 1 year ago
parent
commit
3ce1930068

+ 11 - 1
InABox.Core/EntityLink.cs

@@ -20,7 +20,7 @@ namespace InABox.Core
     {
     }
 
-    public abstract class EntityLink<T> : BaseObject, IEntityLink<T> where T : BaseObject, new()
+    public abstract class EntityLink<T> : BaseObject, IEntityLink<T> where T : Entity, new()
     {
         /*
         private Func<BaseObject>? _linkedentity;
@@ -74,6 +74,16 @@ namespace InABox.Core
             Synchronise(other);
         }
 
+        /// <summary>
+        /// Basically do the same as <see cref="Synchronise(object)"/>, but also copy the <see cref="ID"/>.
+        /// </summary>
+        /// <param name="other">The link to copy data from.</param>
+        public void CopyFrom(T other)
+        {
+            ID = other.ID;
+            Synchronise(other);
+        }
+
         public virtual bool Synchronise(object Entity)
         {
             var result = false;

+ 2 - 2
inabox.wpf/DynamicGrid/DynamicEditorForm/EmbeddedDynamicEditorForm.xaml.cs

@@ -37,7 +37,7 @@ namespace InABox.DynamicGrid
 
         public delegate void CancelEvent();
 
-        public DynamicEditorPages Pages { get; private set; } = new();
+        public DynamicEditorPages Pages { get; private set; } = [];
 
         private BaseObject[] _items;
 
@@ -47,7 +47,7 @@ namespace InABox.DynamicGrid
             set
             {
                 _items = value;
-                DynamicEditorFormModel.Slug = Items != null ? Items.Any() ? Items.First().GetType().EntityName().Split('.').Last() : "" : "";
+                DynamicEditorFormModel.Slug = Items?.FirstOrDefault()?.GetType().EntityName().Split('.').Last() ?? "";
                 Editor.Load(Pages);
                 foreach (var page in Pages)
                     page.OnChanged += (sender, args) => DoChanged();

+ 512 - 519
inabox.wpf/DynamicGrid/DynamicEditorGrid.xaml.cs

@@ -7,732 +7,725 @@ using System.Windows.Controls;
 using System.Windows.Media;
 using InABox.Clients;
 using InABox.Core;
+using InABox.Wpf;
 using InABox.WPF;
 using NPOI.HSSF.Record.Aggregates;
 
-namespace InABox.DynamicGrid
-{
-    public delegate void OnUpdateOtherEditorHandler(string columnname, object value);
+namespace InABox.DynamicGrid;
 
-    public delegate Dictionary<string, object?> EditorValueChangedHandler(IDynamicEditorForm sender, string name, object value);
+public delegate void OnUpdateOtherEditorHandler(string columnname, object value);
 
-    /// <summary>
-    ///     Interaction logic for DynamicEditorGrid.xaml
-    /// </summary>
-    public partial class DynamicEditorGrid : UserControl, IDynamicEditorHost
-    {
-        public delegate void EditorCreatedHandler(object sender, double height, double width);
+public delegate Dictionary<string, object?> EditorValueChangedHandler(IDynamicEditorForm sender, string name, object value);
 
-        public delegate object? GetPropertyValueHandler(object sender, string name);
+/// <summary>
+///     Interaction logic for DynamicEditorGrid.xaml
+/// </summary>
+public partial class DynamicEditorGrid : UserControl, IDynamicEditorHost
+{
+    public delegate void EditorCreatedHandler(object sender, double height, double width);
 
-        public delegate void SetPropertyValueHandler(object sender, string name, object value);
+    public delegate object? GetPropertyValueHandler(object sender, string name);
 
-        public delegate BaseObject[] GetItemsEvent();
+    public delegate void SetPropertyValueHandler(object sender, string name, object value);
 
-        // Column Definitions as defined by calling model
-        private DynamicGridColumns _columns = new();
+    public delegate BaseObject[] GetItemsEvent();
 
-        private Type? LayoutType;
-        private DynamicEditorGridLayout? Layout;
+    // Column Definitions as defined by calling model
+    private DynamicGridColumns _columns = new();
 
-        private bool _tabStripVisible = true;
-        
-        public bool TabStripVisible
+    private Type? LayoutType;
+    private DynamicEditorGridLayout? Layout;
+
+    private bool _tabStripVisible = true;
+    
+    public bool TabStripVisible
+    {
+        get { return _tabStripVisible; }
+        set
         {
-            get { return _tabStripVisible; }
-            set
-            {
-                _tabStripVisible = value;
-                if (Layout != null) 
-                    Layout.TabStripVisible = value;
-            }
+            _tabStripVisible = value;
+            if (Layout != null) 
+                Layout.TabStripVisible = value;
         }
+    }
 
-        public DynamicEditorGrid()
-        {
-            InitializeComponent();
+    public DynamicEditorGrid()
+    {
+        InitializeComponent();
 
-            Loaded += DynamicEditorGrid_Loaded;
-        }
+        Loaded += DynamicEditorGrid_Loaded;
+    }
 
-        private DynamicEditorPages _pages = new();
-        public IEnumerable<IDynamicEditorPage> Pages => _pages;
+    private DynamicEditorPages _pages = new();
+    public IEnumerable<IDynamicEditorPage> Pages => _pages;
 
-        private void AddPage(IDynamicEditorPage page)
+    private void AddPage(IDynamicEditorPage page)
+    {
+        page.ReadOnly = ReadOnly;
+        _pages.Add(page);
+    }
+    private void SetPages(DynamicEditorPages pages)
+    {
+        _pages = pages;
+        foreach (var page in _pages)
         {
             page.ReadOnly = ReadOnly;
-            _pages.Add(page);
-        }
-        private void SetPages(DynamicEditorPages pages)
-        {
-            _pages = pages;
-            foreach (var page in _pages)
-            {
-                page.ReadOnly = ReadOnly;
-            }
         }
+    }
 
-        public bool PreloadPages { get; set; }
+    public bool PreloadPages { get; set; }
 
-        public Type UnderlyingType { get; set; }
+    public Type UnderlyingType { get; set; }
 
-        public OnLoadPage? OnLoadPage { get; set; }
-        public event OnSelectPage? OnSelectPage;
-        public event OnUnloadPage? OnUnloadPage;
+    public OnLoadPage? OnLoadPage { get; set; }
+    public event OnSelectPage? OnSelectPage;
+    public event OnUnloadPage? OnUnloadPage;
 
-        public DynamicGridColumns Columns => _columns;
+    public DynamicGridColumns Columns => _columns;
 
-        private bool _readOnly;
-        public bool ReadOnly
+    private bool _readOnly;
+    public bool ReadOnly
+    {
+        get => _readOnly;
+        set
         {
-            get => _readOnly;
-            set
+            _readOnly = value;
+            foreach(var page in Pages)
             {
-                _readOnly = value;
-                foreach(var page in Pages)
-                {
-                    page.ReadOnly = value;
-                }
+                page.ReadOnly = value;
             }
         }
+    }
 
-        public IEnumerable<IDynamicEditorControl> Editors
+    public IEnumerable<IDynamicEditorControl> Editors
+    {
+        get
         {
-            get
+            foreach (var page in Pages)
             {
-                foreach (var page in Pages)
+                if (page is DynamicEditPage editPage)
                 {
-                    if (page is DynamicEditPage editPage)
+                    foreach(var editor in editPage.Editors)
                     {
-                        foreach(var editor in editPage.Editors)
-                        {
-                            yield return editor;
-                        }
+                        yield return editor;
                     }
                 }
             }
         }
+    }
 
-        public bool TryFindEditor(string columnname, [NotNullWhen(true)] out IDynamicEditorControl? editor)
+    public bool TryFindEditor(string columnname, [NotNullWhen(true)] out IDynamicEditorControl? editor)
+    {
+        foreach (var page in Pages)
         {
-            foreach (var page in Pages)
+            if (page is DynamicEditPage editPage)
             {
-                if (page is DynamicEditPage editPage)
-                {
-                    if (editPage.TryFindEditor(columnname, out editor))
-                        return true;
-                }
+                if (editPage.TryFindEditor(columnname, out editor))
+                    return true;
             }
-            editor = null;
-            return false;
-        }
-        public IDynamicEditorControl? FindEditor(string columnname)
-        {
-            TryFindEditor(columnname, out var editor);
-            return editor;
         }
+        editor = null;
+        return false;
+    }
+    public IDynamicEditorControl? FindEditor(string columnname)
+    {
+        TryFindEditor(columnname, out var editor);
+        return editor;
+    }
 
-        public virtual void ReconfigureEditors()
-        {
-            OnReconfigureEditors?.Invoke(this);
-        }
+    public virtual void ReconfigureEditors()
+    {
+        OnReconfigureEditors?.Invoke(this);
+    }
 
-        public object? GetPropertyValue(string columnname)
-        {
-            return OnGetPropertyValue?.Invoke(this, columnname);
-        }
+    public object? GetPropertyValue(string columnname)
+    {
+        return OnGetPropertyValue?.Invoke(this, columnname);
+    }
 
-        public event EditorCreatedHandler? OnEditorCreated;
+    public event EditorCreatedHandler? OnEditorCreated;
 
-        public event OnCustomiseColumns? OnCustomiseColumns;
+    public event OnCustomiseColumns? OnCustomiseColumns;
 
-        public event OnGetEditor? OnGetEditor;
+    public event OnGetEditor? OnGetEditor;
 
-        public event OnGridCustomiseEditor? OnGridCustomiseEditor;
+    public event OnGridCustomiseEditor? OnGridCustomiseEditor;
 
-        public event OnGetEditorSequence? OnGetSequence;
-        public event GetPropertyValueHandler? OnGetPropertyValue;
-        public event SetPropertyValueHandler? OnSetPropertyValue;
+    public event OnGetEditorSequence? OnGetSequence;
+    public event GetPropertyValueHandler? OnGetPropertyValue;
+    public event SetPropertyValueHandler? OnSetPropertyValue;
 
-        public delegate Dictionary<string, object?> EditorGridValueChangedHandler(DynamicEditorGrid sender, string name, object? value);
-        public event EditorGridValueChangedHandler? OnEditorValueChanged;
+    public delegate Dictionary<string, object?> EditorGridValueChangedHandler(DynamicEditorGrid sender, string name, object? value);
+    public event EditorGridValueChangedHandler? OnEditorValueChanged;
 
-        public event OnAfterEditorValueChanged? OnAfterEditorValueChanged;
+    public event OnAfterEditorValueChanged? OnAfterEditorValueChanged;
 
-        public event OnReconfigureEditors? OnReconfigureEditors;
-        
-        public event OnDefineLookupFilter? OnDefineFilter;
+    public event OnReconfigureEditors? OnReconfigureEditors;
+    
+    public event OnDefineLookupFilter? OnDefineFilter;
 
-        public event OnDefineLookup? OnDefineLookups;
+    public event OnDefineLookup? OnDefineLookups;
 
-        public event GetItemsEvent? GetItems;
+    public event GetItemsEvent? GetItems;
 
-        private void DynamicEditorGrid_Loaded(object sender, RoutedEventArgs e)
-        {
-            //Reload();
-        }
+    private void DynamicEditorGrid_Loaded(object sender, RoutedEventArgs e)
+    {
+        //Reload();
+    }
 
-        public void Reload()
-        {
-            LoadPages();
-            ReconfigureEditors();
-        }
+    public void Reload()
+    {
+        LoadPages();
+        ReconfigureEditors();
+    }
 
-        #region Host Implementation
+    #region Host Implementation
 
-        IEnumerable<DynamicGridColumn> IDynamicEditorHost.Columns => Columns;
+    IEnumerable<DynamicGridColumn> IDynamicEditorHost.Columns => Columns;
 
-        public void LoadColumns(string column, Dictionary<string, string> columns)
+    public void LoadColumns(string column, Dictionary<string, string> columns)
+    {
+        columns.Clear();
+        var comps = column.Split('.').ToList();
+        comps.RemoveAt(comps.Count - 1);
+        var prefix = string.Format("{0}.", string.Join(".", comps));
+        var cols = Columns.Where(x => !x.ColumnName.Equals(column) && x.ColumnName.StartsWith(prefix));
+        foreach (var col in cols)
         {
-            columns.Clear();
-            var comps = column.Split('.').ToList();
-            comps.RemoveAt(comps.Count - 1);
-            var prefix = string.Format("{0}.", string.Join(".", comps));
-            var cols = Columns.Where(x => !x.ColumnName.Equals(column) && x.ColumnName.StartsWith(prefix));
-            foreach (var col in cols)
-            {
-                var subColumn = col.ColumnName[prefix.Length..];
-                columns[subColumn] = col.ColumnName;
-            }
+            var subColumn = col.ColumnName[prefix.Length..];
+            columns[subColumn] = col.ColumnName;
         }
+    }
 
-        public void LoadLookups(ILookupEditorControl editor)
-        {
-            OnDefineLookups?.Invoke(editor);
-        }
+    public void LoadLookups(ILookupEditorControl editor)
+    {
+        OnDefineLookups?.Invoke(editor);
+    }
 
-        BaseObject[] IDynamicEditorHost.GetItems() => GetItems?.Invoke() ?? Array.Empty<BaseObject>();
+    BaseObject[] IDynamicEditorHost.GetItems() => GetItems?.Invoke() ?? Array.Empty<BaseObject>();
 
-        public BaseEditor? GetEditor(DynamicGridColumn column) => OnGetEditor?.Invoke(column);
+    public BaseEditor? GetEditor(DynamicGridColumn column) => OnGetEditor?.Invoke(column);
 
-        public Type GetEditorType() => UnderlyingType;
+    public Type GetEditorType() => UnderlyingType;
 
-        #endregion
+    #endregion
 
-        #region Edit Page
+    #region Edit Page
 
-        public class DynamicEditPage : ContentControl, IDynamicEditorPage
-        {
+    public class DynamicEditPage : ContentControl, IDynamicEditorPage
+    {
 
-            private Grid Grid;
+        private Grid Grid;
 
-            public DynamicEditorGrid EditorGrid { get; set; } = null!; // Set by DynamicEditorGrid
-            public bool Ready { get; set; }
+        public DynamicEditorGrid EditorGrid { get; set; } = null!; // Set by DynamicEditorGrid
+        public bool Ready { get; set; }
 
-            private List<BaseDynamicEditorControl> EditorList { get; set; }
+        private List<BaseDynamicEditorControl> EditorList { get; set; }
 
-            public IEnumerable<IDynamicEditorControl> Editors => EditorList;
+        public IEnumerable<IDynamicEditorControl> Editors => EditorList;
 
-            public PageType PageType => PageType.Editor;
+        public PageType PageType => PageType.Editor;
 
-            public int PageOrder { get; set; }
+        public int PageOrder { get; set; }
 
-            public string Header { get; set; }
+        public string Header { get; set; }
 
-            private double GeneralHeight = 30;
+        private double GeneralHeight = 30;
 
-            private bool _readOnly;
-            public bool ReadOnly
+        private bool _readOnly;
+        public bool ReadOnly
+        {
+            get => _readOnly;
+            set
             {
-                get => _readOnly;
-                set
+                if(_readOnly != value)
                 {
-                    if(_readOnly != value)
+                    _readOnly = value;
+                    foreach(var editor in EditorList)
                     {
-                        _readOnly = value;
-                        foreach(var editor in EditorList)
-                        {
-                            editor.IsEnabled = !value && editor.EditorDefinition.Editable.IsEditable();
-                        }
+                        editor.IsEnabled = !value && editor.EditorDefinition.Editable.IsEditable();
                     }
                 }
             }
+        }
 
-            public DynamicEditPage(string header)
-            {
-                Header = header;
+        public DynamicEditPage(string header)
+        {
+            Header = header;
 
-                EditorList = new List<BaseDynamicEditorControl>();
+            EditorList = [];
 
-                InitialiseContent();
-            }
+            InitialiseContent();
+        }
 
-            public void AddEditor(string columnName, BaseEditor editor)
+        public void AddEditor(string columnName, BaseEditor editor)
+        {
+            BaseDynamicEditorControl? element = DynamicEditorControlFactory.CreateControl(editor, EditorGrid);
+            
+            if (element != null)
             {
-                BaseDynamicEditorControl? element = DynamicEditorControlFactory.CreateControl(editor, EditorGrid);
-                
-                if (element != null)
-                {
-                    element.EditorDefinition = editor;
-
-                    element.IsEnabled = !ReadOnly && editor.Editable.IsEditable();
-
-                    if (!string.IsNullOrWhiteSpace(editor.ToolTip))
-                    {
-                        element.ToolTip = new ToolTip() { Content = editor.ToolTip };
-                    }
+                element.IsEnabled = !ReadOnly && editor.Editable.IsEditable();
 
-                    var label = new Label();
-                    label.Content = CoreUtils.Neatify(editor.Caption); // 2
-                    label.Margin = new Thickness(0F, 0F, 0F, 0F);
-                    label.HorizontalAlignment = HorizontalAlignment.Stretch;
-                    label.VerticalAlignment = VerticalAlignment.Stretch;
-                    label.HorizontalContentAlignment = HorizontalAlignment.Left;
-                    label.VerticalContentAlignment = VerticalAlignment.Center;
-                    label.SetValue(Grid.RowProperty, Grid.RowDefinitions.Count);
-                    label.SetValue(Grid.ColumnProperty, 0);
-                    label.Visibility = string.IsNullOrWhiteSpace(editor.Caption) ? Visibility.Collapsed : Visibility.Visible;
+                if (!string.IsNullOrWhiteSpace(editor.ToolTip))
+                {
+                    element.ToolTip = new ToolTip() { Content = editor.ToolTip };
+                }
 
-                    Grid.Children.Add(label);
+                var label = new Label();
+                label.Content = CoreUtils.Neatify(editor.Caption); // 2
+                label.Margin = new Thickness(0F, 0F, 0F, 0F);
+                label.HorizontalAlignment = HorizontalAlignment.Stretch;
+                label.VerticalAlignment = VerticalAlignment.Stretch;
+                label.HorizontalContentAlignment = HorizontalAlignment.Left;
+                label.VerticalContentAlignment = VerticalAlignment.Center;
+                label.SetValue(Grid.RowProperty, Grid.RowDefinitions.Count);
+                label.SetValue(Grid.ColumnProperty, 0);
+                label.Visibility = string.IsNullOrWhiteSpace(editor.Caption) ? Visibility.Collapsed : Visibility.Visible;
 
-                    element.ColumnName = columnName;
-                    element.Color = editor is UniqueCodeEditor ? Color.FromArgb(0xFF, 0xF6, 0xC9, 0xE8) : Colors.LightYellow;
+                Grid.Children.Add(label);
 
-                    EditorList.Add(element);
+                element.ColumnName = columnName;
+                element.Color = editor is UniqueCodeEditor ? Color.FromArgb(0xFF, 0xF6, 0xC9, 0xE8) : Colors.LightYellow;
 
-                    element.Margin = new Thickness(5F, 2.5F, 5F, 2.5F);
+                EditorList.Add(element);
 
-                    double iHeight = element.DesiredHeight();
-                    if (iHeight == int.MaxValue)
-                    {
-                        Grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) });
-                        GeneralHeight += element.MinHeight + 5.0F;
-                    }
-                    else
-                    {
-                        Grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(iHeight + 5.0F) });
-                        GeneralHeight += iHeight + 5.0F;
-                    }
+                element.Margin = new Thickness(5F, 2.5F, 5F, 2.5F);
 
-                    double iWidth = element.DesiredWidth();
-                    if (iWidth == int.MaxValue)
-                    {
-                        element.HorizontalAlignment = HorizontalAlignment.Stretch;
-                    }
-                    else
-                    {
-                        element.HorizontalAlignment = HorizontalAlignment.Left;
-                        element.Width = iWidth;
-                    }
-
-                    element.SetValue(Grid.RowProperty, Grid.RowDefinitions.Count - 1);
-                    element.SetValue(Grid.ColumnProperty, 1);
-                    Grid.Children.Add(element);
+                double iHeight = element.DesiredHeight();
+                if (iHeight == int.MaxValue)
+                {
+                    Grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) });
+                    GeneralHeight += element.MinHeight + 5.0F;
                 }
-            }
-
-            [MemberNotNull(nameof(Grid))]
-            private void InitialiseContent()
-            {
-                Grid = new Grid
+                else
                 {
-                    HorizontalAlignment = HorizontalAlignment.Stretch,
-                    VerticalAlignment = VerticalAlignment.Stretch,
-                    Margin = new Thickness(0, 2.5, 0, 2.5)
-                };
-                Grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Auto) });
-                Grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
-
-                var scroll = new ScrollViewer
+                    Grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(iHeight + 5.0F) });
+                    GeneralHeight += iHeight + 5.0F;
+                }
+
+                double iWidth = element.DesiredWidth();
+                if (iWidth == int.MaxValue)
                 {
-                    HorizontalAlignment = HorizontalAlignment.Stretch,
-                    VerticalAlignment = VerticalAlignment.Stretch,
-                    VerticalScrollBarVisibility = ScrollBarVisibility.Auto,
-                    Padding = new Thickness(2),
-                    Content = Grid
-                };
-
-                var border = new Border
+                    element.HorizontalAlignment = HorizontalAlignment.Stretch;
+                }
+                else
                 {
-                    BorderBrush = new SolidColorBrush(Colors.Gray),
-                    Background = new SolidColorBrush(Colors.White),
-                    BorderThickness = new Thickness(0.75),
-                    Child = scroll
-                };
+                    element.HorizontalAlignment = HorizontalAlignment.Left;
+                    element.Width = iWidth;
+                }
 
-                Content = border;
+                element.SetValue(Grid.RowProperty, Grid.RowDefinitions.Count - 1);
+                element.SetValue(Grid.ColumnProperty, 1);
+                Grid.Children.Add(element);
             }
+        }
 
-            public void AfterSave(object item)
+        [MemberNotNull(nameof(Grid))]
+        private void InitialiseContent()
+        {
+            Grid = new Grid
             {
-            }
+                HorizontalAlignment = HorizontalAlignment.Stretch,
+                VerticalAlignment = VerticalAlignment.Stretch,
+                Margin = new Thickness(0, 2.5, 0, 2.5)
+            };
+            Grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Auto) });
+            Grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
+
+            var scroll = new ScrollViewer
+            {
+                HorizontalAlignment = HorizontalAlignment.Stretch,
+                VerticalAlignment = VerticalAlignment.Stretch,
+                VerticalScrollBarVisibility = ScrollBarVisibility.Auto,
+                Padding = new Thickness(2),
+                Content = Grid
+            };
+
+            var border = new Border
+            {
+                BorderBrush = new SolidColorBrush(Colors.Gray),
+                Background = new SolidColorBrush(Colors.White),
+                BorderThickness = new Thickness(0.75),
+                Child = scroll
+            };
 
-            public event EventHandler? OnChanged;
+            Content = border;
+        }
 
-            public void BeforeSave(object item)
-            {
-            }
+        public void AfterSave(object item)
+        {
+        }
 
-            public string Caption() => Header;
+        public event EventHandler? OnChanged;
 
-            public bool TryFindEditor(string columnname, [NotNullWhen(true)] out IDynamicEditorControl? editor)
-            {
-                editor = EditorList.FirstOrDefault(x => x.ColumnName.Equals(columnname));
-                editor ??= EditorList.FirstOrDefault(x => columnname.StartsWith(x.ColumnName + '.'));
-                return editor is not null;
-            }
+        public void BeforeSave(object item)
+        {
+        }
 
-            public IEnumerable<BaseDynamicEditorControl> FindEditors(DynamicGridColumn column)
+        public string Caption() => Header;
+
+        public bool TryFindEditor(string columnname, [NotNullWhen(true)] out IDynamicEditorControl? editor)
+        {
+            editor = EditorList.FirstOrDefault(x => x.ColumnName.Equals(columnname));
+            editor ??= EditorList.FirstOrDefault(x => columnname.StartsWith(x.ColumnName + '.'));
+            return editor is not null;
+        }
+
+        public IEnumerable<BaseDynamicEditorControl> FindEditors(DynamicGridColumn column)
+        {
+            return EditorList.Where(x => string.Equals(x.ColumnName, column.ColumnName));
+        }
+
+        #region Configure Editors
+
+        private void Lookup_OnUpdateOtherEditor(string columnname, object value)
+        {
+            var editor = EditorList.FirstOrDefault(x => x.ColumnName.Equals(columnname));
+            if (editor != null)
+                CoreUtils.SetPropertyValue(editor, "Value", value);
+        }
+
+        private void ConfigureEditors()
+        {
+            foreach (var editor in EditorList)
             {
-                return EditorList.Where(x => string.Equals(x.ColumnName, column.ColumnName));
+                editor.Configure();
+                editor.Loaded = true;
             }
+        }
 
-            #region Configure Editors
+        #endregion
+
+        private void EditorValueChanged(IDynamicEditorControl sender, Dictionary<string, object?> values)
+        {
+            //Logger.Send(LogType.Information, "", string.Format("DynamicEditorGrid.EditorValueChanged({0})", values.Keys.Count));
+            var changededitors = new Dictionary<string, object?>();
 
-            private void Lookup_OnUpdateOtherEditor(string columnname, object value)
+            void ExtractChanged(Dictionary<string, object?>? columns)
             {
-                var editor = EditorList.FirstOrDefault(x => x.ColumnName.Equals(columnname));
-                if (editor != null)
-                    CoreUtils.SetPropertyValue(editor, "Value", value);
+                if (columns != null)
+                    foreach (var (change, value) in columns)
+                        if (!changededitors.ContainsKey(change) && !change.Equals(sender.ColumnName))
+                            changededitors[change] = value;
             }
 
-            private void ConfigureEditors()
+            var name = sender.ColumnName;
+            var resetAll = false;
+            if(values.Remove(name, out var value))
             {
-                foreach (var Editor in EditorList)
-                {
-                    var editor = Editor.EditorDefinition;
-                    var column = Editor.ColumnName;
+                var changedcolumns = EditorGrid.OnEditorValueChanged?.Invoke(EditorGrid, name, value);
 
-                    Editor.Configure();
-                    if (!EditorList.Any(x => x.ColumnName.Equals(Editor.ColumnName)))
-                        EditorList.Add(Editor);
-                    Editor.Loaded = true;
-                }
+                resetAll = changedcolumns?.ContainsKey(name) ?? false;
+                ExtractChanged(changedcolumns);
             }
-
-            #endregion
-
-            private void EditorValueChanged(IDynamicEditorControl sender, Dictionary<string, object?> values)
+            else
             {
-                //Logger.Send(LogType.Information, "", string.Format("DynamicEditorGrid.EditorValueChanged({0})", values.Keys.Count));
-                var changededitors = new Dictionary<string, object?>();
-
-                void ExtractChanged(Dictionary<string, object?>? columns)
-                {
-                    if (columns != null)
-                        foreach (var (change, value) in columns)
-                            if (!changededitors.ContainsKey(change) && !change.Equals(sender.ColumnName))
-                                changededitors[change] = value;
-                }
-
-                var name = sender.ColumnName;
-                var resetAll = false;
-                if(values.Remove(name, out var value))
-                {
-                    var changedcolumns = EditorGrid.OnEditorValueChanged?.Invoke(EditorGrid, name, value);
 
-                    resetAll = changedcolumns?.ContainsKey(name) ?? false;
-                    ExtractChanged(changedcolumns);
-                }
-                else
-                {
-
-                }
+            }
 
-                foreach (var (key, otherValue) in values)
+            foreach (var (key, otherValue) in values)
+            {
+                var changes = new Dictionary<string, object?>();
+                if (resetAll)
                 {
-                    var changes = new Dictionary<string, object?>();
-                    if (resetAll)
+                    var prop = DatabaseSchema.Property(EditorGrid.UnderlyingType, key);
+                    if(prop is not null)
                     {
-                        var prop = DatabaseSchema.Property(EditorGrid.UnderlyingType, key);
-                        if(prop is not null)
+                        var def = CoreUtils.GetDefault(prop.PropertyType);
+                        var resetChanges = EditorGrid.OnEditorValueChanged?.Invoke(EditorGrid, key, def);
+                        if(resetChanges is not null)
                         {
-                            var def = CoreUtils.GetDefault(prop.PropertyType);
-                            var resetChanges = EditorGrid.OnEditorValueChanged?.Invoke(EditorGrid, key, def);
-                            if(resetChanges is not null)
-                            {
-                                changes = resetChanges;
-                            }
+                            changes = resetChanges;
                         }
-                        else
-                        {
+                    }
+                    else
+                    {
 
-                        }
                     }
-                    var changedOtherColumns = EditorGrid.OnEditorValueChanged?.Invoke(EditorGrid, key, otherValue);
+                }
+                var changedOtherColumns = EditorGrid.OnEditorValueChanged?.Invoke(EditorGrid, key, otherValue);
 
-                    if(changedOtherColumns is not null)
+                if(changedOtherColumns is not null)
+                {
+                    foreach (var (k, v) in changedOtherColumns)
                     {
-                        foreach (var (k, v) in changedOtherColumns)
-                        {
-                            changes[k] = v;
-                        }
+                        changes[k] = v;
                     }
-
-                    ExtractChanged(changes);
                 }
 
-                var afterchanged = EditorGrid.OnAfterEditorValueChanged?.Invoke(EditorGrid, new AfterEditorValueChangedArgs(sender.ColumnName, changededitors));
-                ExtractChanged(afterchanged);
+                ExtractChanged(changes);
+            }
 
-                if (changededitors.Any())
-                    LoadEditorValues(changededitors);
+            var afterchanged = EditorGrid.OnAfterEditorValueChanged?.Invoke(EditorGrid, new AfterEditorValueChangedArgs(sender.ColumnName, changededitors));
+            ExtractChanged(afterchanged);
 
-                EditorGrid.ReconfigureEditors();
-            }
+            if (changededitors.Count != 0)
+                LoadEditorValues(changededitors);
+
+            EditorGrid.ReconfigureEditors();
+        }
 
-            private void LoadEditorValues(Dictionary<string, object?>? changededitors = null)
+        private void LoadEditorValues(Dictionary<string, object?>? changededitors = null)
+        {
+            var columnnames = changededitors != null ? changededitors.Keys.ToArray() : EditorList.Select(x => x.ColumnName).ToArray();
+            foreach (var columnname in columnnames)
             {
-                var columnnames = changededitors != null ? changededitors.Keys.ToArray() : EditorList.Select(x => x.ColumnName).ToArray();
-                foreach (var columnname in columnnames)
+                if (!TryFindEditor(columnname, out var editor))
+                    continue;
+
+                var bLoaded = editor.Loaded;
+                editor.Loaded = false;
+                if (changededitors != null && changededitors.ContainsKey(columnname))
+                {
+                    editor.SetValue(columnname, changededitors[columnname]);
+                }
+                else
                 {
-                    if (!TryFindEditor(columnname, out var editor))
-                        continue;
+                    var curvalue = EditorGrid.GetPropertyValue(columnname);
 
-                    var bLoaded = editor.Loaded;
-                    editor.Loaded = false;
-                    if (changededitors != null && changededitors.ContainsKey(columnname))
+                    try
                     {
-                        editor.SetValue(columnname, changededitors[columnname]);
+                        editor.SetValue(columnname, curvalue);
                     }
-                    else
+                    catch (Exception e)
                     {
-                        var curvalue = EditorGrid.GetPropertyValue(columnname);
-
-                        try
-                        {
-                            editor.SetValue(columnname, curvalue);
-                        }
-                        catch (Exception e)
-                        {
-                            MessageBox.Show($"Unable to set editor value for {columnname} -> {curvalue}: {CoreUtils.FormatException(e)}");
-                        }
-
-                        editor.Changed = false;
+                        MessageWindow.ShowError($"Unable to set editor value for {columnname} -> {curvalue}", e);
                     }
 
-                    editor.Loaded = bLoaded;
-
-                    editor.OnEditorValueChanged += EditorValueChanged;
+                    editor.Changed = false;
                 }
+
+                editor.Loaded = bLoaded;
+
+                editor.OnEditorValueChanged += EditorValueChanged;
             }
+        }
 
-            public void Load(object item, Func<Type, CoreTable?>? PageDataHandler)
-            {
-                ConfigureEditors();
-                LoadEditorValues();
+        public void Load(object item, Func<Type, CoreTable?>? PageDataHandler)
+        {
+            ConfigureEditors();
+            LoadEditorValues();
 
-                foreach (var editor in EditorList)
+            foreach (var editor in EditorList)
+            {
+                foreach(var (column, editorValue) in editor.GetValues())
                 {
-                    foreach(var (column, editorValue) in editor.GetValues())
+                    var entityValue = EditorGrid.GetPropertyValue(column);
+                    if (!Equals(editorValue, entityValue))
                     {
-                        var entityValue = EditorGrid.GetPropertyValue(column);
-                        if (!Equals(editorValue, entityValue))
-                        {
-                            bool bLoaded = editor.Loaded;
-                            editor.Loaded = false;
-                            editor.SetValue(column, entityValue);
-                            editor.Loaded = bLoaded;
-                        }
+                        bool bLoaded = editor.Loaded;
+                        editor.Loaded = false;
+                        editor.SetValue(column, entityValue);
+                        editor.Loaded = bLoaded;
                     }
                 }
-
-                EditorList.FirstOrDefault()?.SetFocus();
-
-                Ready = true;
             }
 
-            public void DoChanged()
-            {
-                OnChanged?.Invoke(this, EventArgs.Empty);
-            }
+            EditorList.FirstOrDefault()?.SetFocus();
 
-            public Size MinimumSize() => new Size(800, GeneralHeight);
+            Ready = true;
+        }
 
-            public int Order() => PageOrder;
+        public void DoChanged()
+        {
+            OnChanged?.Invoke(this, EventArgs.Empty);
         }
 
-        #endregion
+        public Size MinimumSize() => new Size(800, GeneralHeight);
 
-        #region Loading + Editing Layout
+        public int Order() => PageOrder;
+    }
 
-        private decimal GetSequence(DynamicGridColumn column)
-        {
-            if (OnGetSequence != null)
-                return OnGetSequence.Invoke(column);
-            return 999;
-        }
+    #endregion
 
-        private DynamicEditPage GetEditPage(string name)
+    #region Loading + Editing Layout
+
+    private decimal GetSequence(DynamicGridColumn column)
+    {
+        if (OnGetSequence != null)
+            return OnGetSequence.Invoke(column);
+        return 999;
+    }
+
+    private DynamicEditPage GetEditPage(string name)
+    {
+        var page = Pages.Where(x => x is DynamicEditPage page && page.Header == name).FirstOrDefault() as DynamicEditPage;
+        if(page is null)
         {
-            var page = Pages.Where(x => x is DynamicEditPage page && page.Header == name).FirstOrDefault() as DynamicEditPage;
-            if(page is null)
+            page = new DynamicEditPage(name)
             {
-                page = new DynamicEditPage(name)
-                {
-                    // Setting this here because it's needed now to be able to create the layout.
-                    EditorGrid = this
-                };
-                if (name == "General")
-                {
-                    page.PageOrder = -1;
-                }
-                else
-                {
-                    page.PageOrder = 0;
-                }
-
-                AddPage(page);
+                // Setting this here because it's needed now to be able to create the layout.
+                EditorGrid = this
+            };
+            if (name == "General")
+            {
+                page.PageOrder = -1;
+            }
+            else
+            {
+                page.PageOrder = 0;
             }
-            return page;
-        }
 
-        public void SetLayoutType<T>() where T : DynamicEditorGridLayout
-        {
-            LayoutType = typeof(T);
+            AddPage(page);
         }
+        return page;
+    }
 
-        public void SetLayoutType(Type t)
-        {
-            if (!t.IsSubclassOf(typeof(DynamicEditorGridLayout)))
-                throw new Exception($"{t.Name} is not a {nameof(DynamicEditorGridLayout)}!");
-            LayoutType = t;
-        }
+    public void SetLayoutType<T>() where T : DynamicEditorGridLayout
+    {
+        LayoutType = typeof(T);
+    }
 
-        private void InitialiseLayout()
-        {
-            Layout = (Activator.CreateInstance(LayoutType ?? typeof(DefaultDynamicEditorGridLayout)) as DynamicEditorGridLayout)!;
-            Layout.OnSelectPage += Layout_SelectPage;
-            Layout.TabStripVisible = _tabStripVisible;
+    public void SetLayoutType(Type t)
+    {
+        if (!t.IsSubclassOf(typeof(DynamicEditorGridLayout)))
+            throw new Exception($"{t.Name} is not a {nameof(DynamicEditorGridLayout)}!");
+        LayoutType = t;
+    }
 
-            Content = Layout;
+    private void InitialiseLayout()
+    {
+        Layout = (Activator.CreateInstance(LayoutType ?? typeof(DefaultDynamicEditorGridLayout)) as DynamicEditorGridLayout)!;
+        Layout.OnSelectPage += Layout_SelectPage;
+        Layout.TabStripVisible = _tabStripVisible;
+
+        Content = Layout;
+    }
+
+    private void CreateLayout()
+    {
+        if(Layout is null)
+        {
+            InitialiseLayout();
         }
 
-        private void CreateLayout()
+        foreach (var column in _columns.OrderBy(x => GetSequence(x)))
         {
-            if(Layout is null)
+            var iProp = DatabaseSchema.Property(UnderlyingType, column.ColumnName);
+            var editor = OnGetEditor?.Invoke(column);
+
+            if (editor != null && iProp?.ShouldShowEditor() != true)
             {
-                InitialiseLayout();
+                editor.Visible = Visible.Hidden;
+                editor.Editable = Editable.Hidden;
             }
 
-            foreach (var column in _columns.OrderBy(x => GetSequence(x)))
+            if(editor is not null)
             {
-                var iProp = DatabaseSchema.Property(UnderlyingType, column.ColumnName);
-                var editor = OnGetEditor?.Invoke(column);
-
-                if (editor != null && iProp?.ShouldShowEditor() != true)
+                foreach(var security in editor.Security)
                 {
-                    editor.Visible = Visible.Hidden;
-                    editor.Editable = Editable.Hidden;
-                }
-
-                if(editor is not null)
-                {
-                    foreach(var security in editor.Security)
+                    if (!Security.IsAllowed(security.SecurityDescriptor))
                     {
-                        if (!Security.IsAllowed(security.SecurityDescriptor))
+                        editor.Editable = editor.Editable.Combine(security.Editable);
+                        if (editor.Editable == Editable.Hidden)
                         {
-                            editor.Editable = editor.Editable.Combine(security.Editable);
-                            if (editor.Editable == Editable.Hidden)
-                            {
-                                break;
-                            }
+                            break;
                         }
                     }
                 }
+            }
 
-                if(editor is not null)
-                {
-                    OnGridCustomiseEditor?.Invoke(this, column, editor);
-                }
+            if(editor is not null)
+            {
+                OnGridCustomiseEditor?.Invoke(this, column, editor);
+            }
 
-                if (editor != null && editor.Editable.EditorVisible())
-                {
-                    var page = string.IsNullOrWhiteSpace(editor.Page) ? iProp is StandardProperty ? "General" : "Custom Fields" : editor.Page;
-                    var editPage = GetEditPage(page);
+            if (editor != null && editor.Editable.EditorVisible())
+            {
+                var page = string.IsNullOrWhiteSpace(editor.Page) ? iProp is StandardProperty ? "General" : "Custom Fields" : editor.Page;
+                var editPage = GetEditPage(page);
 
-                    editPage.AddEditor(column.ColumnName, editor);
-                }
-                else if (iProp?.HasParentEditor() == true)
+                editPage.AddEditor(column.ColumnName, editor);
+            }
+            else if (iProp?.HasParentEditor() == true)
+            {
+                // Add the parent editor if it hasn't been added already.
+                var parent = iProp.GetParentWithEditor();
+                if(parent is not null)
                 {
-                    // Add the parent editor if it hasn't been added already.
-                    var parent = iProp.GetParentWithEditor();
-                    if(parent is not null)
-                    {
-                        var parentEditor = parent.Editor;
+                    var parentEditor = parent.Editor;
 
-                        if(parentEditor is not null)
-                        {
-                            OnGridCustomiseEditor?.Invoke(this, new DynamicGridColumn { ColumnName = parent.Name }, parentEditor);
-                        }
-                        if(parentEditor is not null && parentEditor.Editable.EditorVisible())
+                    if(parentEditor is not null)
+                    {
+                        OnGridCustomiseEditor?.Invoke(this, new DynamicGridColumn { ColumnName = parent.Name }, parentEditor);
+                    }
+                    if(parentEditor is not null && parentEditor.Editable.EditorVisible())
+                    {
+                        var page = string.IsNullOrWhiteSpace(parentEditor.Page)
+                            ? parent is StandardProperty
+                                ? "General"
+                                : "Custom Fields"
+                            : parentEditor.Page;
+
+                        var editPage = GetEditPage(page);
+                        if (!editPage.TryFindEditor(parent.Name, out var editorControl))
                         {
-                            var page = string.IsNullOrWhiteSpace(parentEditor.Page)
-                                ? parent is StandardProperty
-                                    ? "General"
-                                    : "Custom Fields"
-                                : parentEditor.Page;
-
-                            var editPage = GetEditPage(page);
-                            if (!editPage.TryFindEditor(parent.Name, out var editorControl))
-                            {
-                                editPage.AddEditor(parent.Name, parentEditor);
-                            }
+                            editPage.AddEditor(parent.Name, parentEditor);
                         }
                     }
                 }
             }
-            
-            OnEditorCreated?.Invoke(this, 0, 800);
         }
+        
+        OnEditorCreated?.Invoke(this, 0, 800);
+    }
 
-        #endregion
+    #endregion
 
-        #region Pages
+    #region Pages
 
-        private void Layout_SelectPage(IDynamicEditorPage page)
-        {
-            if (!page.Ready)
-                using (new WaitCursor())
-                {
-                    OnLoadPage?.Invoke(page);
-                }
+    private void Layout_SelectPage(IDynamicEditorPage page)
+    {
+        if (!page.Ready)
+            using (new WaitCursor())
+            {
+                OnLoadPage?.Invoke(page);
+            }
 
-            OnSelectPage?.Invoke(this, null);
-        }
+        OnSelectPage?.Invoke(this, null);
+    }
 
-        public void UnloadPages(bool saved)
-        {
-            if(Pages is not null)
-                foreach (var page in Pages)
-                    if (page.Ready)
-                        OnUnloadPage?.Invoke(page, saved);
-        }
+    public void UnloadPages(bool saved)
+    {
+        if(Pages is not null)
+            foreach (var page in Pages)
+                if (page.Ready)
+                    OnUnloadPage?.Invoke(page, saved);
+    }
 
-        private void LoadPages()
-        {
-            if (Pages != null && Layout is not null)
-                using (new WaitCursor())
+    private void LoadPages()
+    {
+        if (Pages != null && Layout is not null)
+            using (new WaitCursor())
+            {
+                foreach (var page in Pages)
                 {
-                    foreach (var page in Pages)
-                    {
-                        page.Ready = false;
-                        page.EditorGrid = this;
-                    }
-                    Layout.LoadPages(Pages);
+                    page.Ready = false;
+                    page.EditorGrid = this;
+                }
+                Layout.LoadPages(Pages);
 
-                    if (PreloadPages)
+                if (PreloadPages)
+                {
+                    foreach(var page in Pages)
                     {
-                        foreach(var page in Pages)
-                        {
-                            OnLoadPage?.Invoke(page);
-                        }
+                        OnLoadPage?.Invoke(page);
                     }
                 }
-        }
+            }
+    }
 
-        public void Load(DynamicEditorPages pages)
-        {
-            SetPages(pages);
+    public void Load(DynamicEditorPages pages)
+    {
+        SetPages(pages);
 
-            _columns = new DynamicGridColumns();
-            OnCustomiseColumns?.Invoke(this, _columns);
+        _columns = new DynamicGridColumns();
+        OnCustomiseColumns?.Invoke(this, _columns);
 
-            CreateLayout();
-            Reload();
-        }
+        CreateLayout();
+        Reload();
+    }
 
-        #endregion
+    #endregion
 
-    }
 }

+ 7 - 2
inabox.wpf/DynamicGrid/DynamicGrid.cs

@@ -1271,6 +1271,12 @@ public abstract class DynamicGrid<T> : DynamicGrid, IDynamicGridUIComponentParen
             InvalidateRow(row);
     }
 
+    public void UpdateRow(CoreRow row, T obj)
+    {
+        ObjectToRow(obj, row);
+        ObjectToRow(obj, _recordmap[row]);
+    }
+
 
     public void AddRow(CoreRow row)
     {
@@ -1825,8 +1831,7 @@ public abstract class DynamicGrid<T> : DynamicGrid, IDynamicGridUIComponentParen
             {
                 for (var i = 0; i < items.Length; i++)
                 {
-                    ObjectToRow(items[i], rows[i]);
-                    ObjectToRow(items[i], _recordmap[rows[i]]);
+                    UpdateRow(rows[i], items[i]);
                 }
                 InvalidateGrid();
                 SelectedRows = sel;

+ 11 - 0
inabox.wpf/DynamicGrid/DynamicTabControl.cs

@@ -130,6 +130,7 @@ namespace InABox.DynamicGrid
         public static readonly DependencyProperty TabStripVisibleProperty =
             DependencyProperty.Register(nameof(TabStripVisible), typeof(bool), typeof(DynamicTabControl), new PropertyMetadata(true));
 
+        private double _tabStripHeight;
         public bool TabStripVisible
         {
             get => (bool)GetValue(TabStripVisibleProperty);
@@ -139,6 +140,16 @@ namespace InABox.DynamicGrid
                 Style s = new Style();
                 s.Setters.Add(new Setter(UIElement.VisibilityProperty, value ? Visibility.Visible : Visibility.Collapsed));
                 ItemContainerStyle = s;
+
+                if (!value)
+                {
+                    _tabStripHeight = TabStripHeight;
+                    TabStripHeight = 0;
+                }
+                else if(TabStripHeight == 0)
+                {
+                    TabStripHeight = _tabStripHeight;
+                }
             }
         }
         

+ 4 - 25
inabox.wpf/DynamicGrid/Editors/DynamicEditorControlFactory.cs

@@ -12,23 +12,11 @@ namespace InABox.DynamicGrid
 
         private static Dictionary<Type, Type>? _editors;
 
-        public static void Register<TControl, TEditorBase, TEditor>() 
-            where TEditor : TEditorBase
-            where TEditorBase : IBaseEditor
-            where TControl : BaseDynamicEditorControl<TEditorBase>, new()
-        {
-            _editors[typeof(TEditor)] = typeof(TControl);
-        }
-        public static void Register<TControl, TEditor>()
-            where TEditor : BaseEditor
-            where TControl : BaseDynamicEditorControl<TEditor>, new()
-            => Register<TControl, TEditor, TEditor>();
-
         private static Dictionary<Type, Type> GetEditors()
         {
             if(_editors is null)
             {
-                _editors = new();
+                _editors = [];
                 foreach(var type in CoreUtils.TypeList(AppDomain.CurrentDomain.GetAssemblies(),
                     x => x.IsClass
                         && !x.IsAbstract
@@ -74,20 +62,11 @@ namespace InABox.DynamicGrid
             {
                 var result = Activator.CreateInstance(TControl) as BaseDynamicEditorControl;
                 if (result != null)
+                {
                     result.Host = host;
-                return result;
-            }
+                    result.EditorDefinition = editor;
+                }
 
-            return null;
-        }
-        
-        public static BaseDynamicEditorControl? CreateControl<TEditor>(IDynamicEditorHost host) where TEditor : BaseEditor
-        {
-            if (GetControlType(typeof(TEditor), out var TControl))
-            {
-                var result = Activator.CreateInstance(TControl) as BaseDynamicEditorControl;
-                if (result != null)
-                    result.Host = host;
                 return result;
             }
 

+ 74 - 75
inabox.wpf/DynamicGrid/Editors/TextBoxEditor/TextBoxEditorControl.cs

@@ -4,98 +4,97 @@ using System.Windows.Controls;
 using System.Windows.Media;
 using InABox.Core;
 
-namespace InABox.DynamicGrid
+namespace InABox.DynamicGrid;
+
+public class TextBoxEditorControl : DynamicEditorControl<string, TextBoxEditor>
 {
-    public class TextBoxEditorControl : DynamicEditorControl<string, TextBoxEditor>
+    
+    static TextBoxEditorControl()
     {
-        
-        static TextBoxEditorControl()
-        {
-            //DynamicEditorControlFactory.Register<TextBoxEditorControl, TextBoxEditor>();
-        }
-        
-        private TextBox Editor;
-
-        private bool IsChanged;
-
-        public override void Configure()
-        {
-        }
-
-        protected override FrameworkElement CreateEditor()
-        {
-            var dock = new DockPanel();
+        //DynamicEditorControlFactory.Register<TextBoxEditorControl, TextBoxEditor>();
+    }
+    
+    private TextBox Editor;
 
-            var buttons = CreateButtons(out var DisableEditor);
-            foreach (var button in buttons)
-            {
-                button.SetValue(DockPanel.DockProperty, Dock.Right);
-                dock.Children.Add(button);
-                dock.Width += button.Width + 5;
-            }
+    private bool IsChanged;
 
-            Editor = new TextBox
-            {
-                VerticalAlignment = VerticalAlignment.Stretch,
-                VerticalContentAlignment = VerticalAlignment.Center,
-                HorizontalAlignment = HorizontalAlignment.Stretch
-            };
-            Editor.SetValue(DockPanel.DockProperty, Dock.Left);
-            if (DisableEditor)
-            {
-                Editor.Background = new SolidColorBrush(Colors.Silver);
-                Editor.IsEnabled = false;
-            }
+    public override void Configure()
+    {
+    }
 
-            Editor.TextChanged += (o, e) =>
-            {
-                if(Loaded)
-                    IsChanged = true;
-                //CheckChanged();
-            };
-            Editor.LostFocus += (o, e) =>
-            {
-                if (IsChanged)
-                    CheckChanged();
-            };
-            dock.Children.Add(Editor);
-            return dock;
-        }
+    protected override FrameworkElement CreateEditor()
+    {
+        var dock = new DockPanel();
 
-        public override int DesiredHeight()
+        var buttons = CreateButtons(out var DisableEditor);
+        foreach (var button in buttons)
         {
-            return 25;
+            button.SetValue(DockPanel.DockProperty, Dock.Right);
+            dock.Children.Add(button);
+            dock.Width += button.Width + 5;
         }
 
-        public override int DesiredWidth()
+        Editor = new TextBox
         {
-            return int.MaxValue;
-        }
-
-        protected override string RetrieveValue()
+            VerticalAlignment = VerticalAlignment.Stretch,
+            VerticalContentAlignment = VerticalAlignment.Center,
+            HorizontalAlignment = HorizontalAlignment.Stretch
+        };
+        Editor.SetValue(DockPanel.DockProperty, Dock.Left);
+        if (DisableEditor)
         {
-            return Editor.Text;
+            Editor.Background = new SolidColorBrush(Colors.Silver);
+            Editor.IsEnabled = false;
         }
 
-        protected override void UpdateValue(string value)
+        Editor.TextChanged += (o, e) =>
         {
-            if (Editor != null && value != Editor.Text)
-            {
-                Editor.Text = value;
-                if (Loaded)
-                    CheckChanged();
-            }
-        }
-
-        public override void SetFocus()
+            if(Loaded)
+                IsChanged = true;
+            //CheckChanged();
+        };
+        Editor.LostFocus += (o, e) =>
         {
-            Editor.Focus();
-            Editor.CaretIndex = string.IsNullOrEmpty(Value) ? 0 : Value.Length;
-        }
+            if (IsChanged)
+                CheckChanged();
+        };
+        dock.Children.Add(Editor);
+        return dock;
+    }
+
+    public override int DesiredHeight()
+    {
+        return 25;
+    }
+
+    public override int DesiredWidth()
+    {
+        return int.MaxValue;
+    }
+
+    protected override string RetrieveValue()
+    {
+        return Editor.Text;
+    }
 
-        public override void SetColor(Color color)
+    protected override void UpdateValue(string value)
+    {
+        if (Editor != null && value != Editor.Text)
         {
-            Editor.Background = new SolidColorBrush(color);
+            Editor.Text = value;
+            if (Loaded)
+                CheckChanged();
         }
     }
+
+    public override void SetFocus()
+    {
+        Editor.Focus();
+        Editor.CaretIndex = string.IsNullOrEmpty(Value) ? 0 : Value.Length;
+    }
+
+    public override void SetColor(Color color)
+    {
+        Editor.Background = new SolidColorBrush(color);
+    }
 }

+ 2 - 1
inabox.wpf/DynamicGrid/UIComponent/DynamicGridGridUIComponent.cs

@@ -565,7 +565,8 @@ public class DynamicGridGridUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
 
     public void ScrollIntoView(CoreRow row)
     {
-        DataGrid.ScrollInView(new RowColumnIndex(row.Index + 1, 0));
+        var rowIdx = DataGrid.ResolveToRowIndex(row.Index + 1);
+        DataGrid.ScrollInView(new RowColumnIndex(rowIdx, 0));
     }
 
     protected virtual Brush? GetCellBackground(CoreRow row, DynamicColumnBase column) => null;

+ 4 - 0
inabox.wpf/Forms/MessageWindow.xaml.cs

@@ -210,6 +210,10 @@ public partial class MessageWindow : Window, INotifyPropertyChanged
 
     public static BitmapImage WarningImage => _warning;
 
+    public static readonly BitmapImage _question = InABox.Wpf.Resources.help.AsBitmapImage();
+
+    public static BitmapImage QuestionImage => _question;
+
     public static MessageWindow New()
     {
         return new MessageWindow();