Ver Fonte

Improvements to ManyToMany add function and fix to duplicate bug.

Kenric Nugteren há 6 meses atrás
pai
commit
7760c0a7b8

+ 256 - 242
inabox.wpf/DynamicGrid/Controls/MultiSelectDialog.cs

@@ -12,290 +12,304 @@ using InABox.Wpf;
 using Syncfusion.Data;
 using Button = System.Windows.Controls.Button;
 
-namespace InABox.DynamicGrid
+namespace InABox.DynamicGrid;
+
+public interface IMultiSelectDialog
 {
-    public interface IMultiSelectDialog
-    {
-        bool ShowDialog(String? column = null, String? filter = null, FilterType filtertype = FilterType.Contains);
-        Guid[] IDs();
-        CoreTable Data();
+    bool ShowDialog(String? column = null, String? filter = null, FilterType filtertype = FilterType.Contains);
+    Guid[] IDs();
+    CoreTable Data();
 
-        Entity[] Items(IColumns? columns = null);
-    }
-    
-    public class MultiSelectDialogSettings : BaseObject, IUserConfigurationSettings
-    {
-        public DynamicGridSelectedFilterSettings Filters { get; set; } = new();
-    }
+    Entity[] Items(IColumns? columns = null);
+}
+
+public class MultiSelectDialogSettings : BaseObject, IUserConfigurationSettings
+{
+    public DynamicGridSelectedFilterSettings Filters { get; set; } = new();
+}
 
-    /// <summary>
-    /// Represents a dialog to select <typeparamref name="T"/>(s), given a filter and a set of columns. It can either do multi-selecting or single-selecting.
-    /// </summary>
-    /// <remarks>
-    /// This is the standard way to do a selection dialog. To access all selected IDs, use <see cref="IDs"/>; to access the data according to the columns
-    /// provided in the constructor, use <see cref="Data"/>; use <see cref="Items"/> if you want to load all the items with the selected IDs with a custom
-    /// set of columns.
-    /// </remarks>
-    public class MultiSelectDialog<T> : IMultiSelectDialog where T : Entity, IRemotable, IPersistent, new()
+/// <summary>
+/// Represents a dialog to select <typeparamref name="T"/>(s), given a filter and a set of columns. It can either do multi-selecting or single-selecting.
+/// </summary>
+/// <remarks>
+/// This is the standard way to do a selection dialog. To access all selected IDs, use <see cref="IDs"/>; to access the data according to the columns
+/// provided in the constructor, use <see cref="Data"/>; use <see cref="Items"/> if you want to load all the items with the selected IDs with a custom
+/// set of columns.
+/// </remarks>
+public class MultiSelectDialog<T> : IMultiSelectDialog where T : Entity, IRemotable, IPersistent, new()
+{
+    //private Expression<Func<T, object>>[] _columns = new Expression<Func<T, object>>[] { };
+    private readonly Columns<T>? _columns;
+
+    private readonly Filter<T>? _filter;
+    private readonly DynamicDataGrid<T> datagrid;
+    private readonly Grid grid;
+    private readonly Button ClearButton;
+    private readonly Button OKButton;
+    private ThemableWindow? window;
+    
+    public MultiSelectDialog(Filter<T>? filter, Columns<T>? columns, bool multiselect = true)
     {
-        //private Expression<Func<T, object>>[] _columns = new Expression<Func<T, object>>[] { };
-        private readonly Columns<T>? _columns;
-
-        private readonly Filter<T>? _filter;
-        private readonly DynamicDataGrid<T> datagrid;
-        private readonly Grid grid;
-        private readonly Button ClearButton;
-        private readonly Button OKButton;
-        private ThemableWindow? window;
         
-        public MultiSelectDialog(Filter<T>? filter, Columns<T>? columns, bool multiselect = true)
-        {
-            
-            _filter = filter;
-
-            grid = new Grid();
-            grid.Margin = new Thickness(5);
-            grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1.0F, GridUnitType.Star) });
-            grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(40.0F, GridUnitType.Pixel) });
-
-            grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(80.0F, GridUnitType.Pixel) });
-            grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1.0F, GridUnitType.Star) });
-            grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(80.0F, GridUnitType.Pixel) });
-            grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(80.0F, GridUnitType.Pixel) });
-
-            datagrid = new DynamicDataGrid<T>();
-            
-            datagrid.Reconfigure(options =>
-            {
-                options.BeginUpdate();
-                options.Clear();
-                options.SelectColumns = true;
-                options.FilterRows = true;
-                if (multiselect)
-                    options.MultiSelect = true;
-                options.EndUpdate();
-            });
-            datagrid.Reconfigure();
-            
-            datagrid.OnReload += Grid_OnReload;
-            datagrid.OnDoubleClick += Grid_DoubleClick;
-            datagrid.ColumnsTag = "MSD";
-            if (columns != null)
-            {
-                _columns = columns;
-                foreach (var column in columns)
-                    datagrid.AddHiddenColumn(column.Property);
-                //datagrid.HiddenColumns.AddRange(columns);
-            }
-            else
-            {
-                var cols = LookupFactory.DefineColumns<T>()
-                    .AddColumns(ColumnTypeFlags.IncludeOptional | ColumnTypeFlags.IncludeForeignKeys | ColumnTypeFlags.IncludeLinked);
-                foreach (var col in cols)
-                    datagrid.AddHiddenColumn(col.ToString());
-            }
+        _filter = filter;
 
-            var _settings = new UserConfiguration<MultiSelectDialogSettings>(datagrid.GetTag()).Load();
-            datagrid.FilterComponent.SetSettings(_settings.Filters,false);
-            datagrid.FilterComponent.OnFiltersSelected += (settings) =>
-            {
-                var _settings = new MultiSelectDialogSettings() { Filters = settings };
-                new UserConfiguration<MultiSelectDialogSettings>(datagrid.GetTag()).Save(_settings);
-            };
-            
-            datagrid.SetValue(Grid.RowProperty, 0);
-            datagrid.SetValue(Grid.ColumnProperty, 0);
-            datagrid.SetValue(Grid.ColumnSpanProperty, 4);
-            datagrid.OnSelectItem += Datagrid_OnSelectItem;
-            grid.Children.Add(datagrid);
-            
-            ClearButton = new Button();
-            ClearButton.Margin = new Thickness(0, 5, 5, 0);
-            ClearButton.Content = "Clear";
-            ClearButton.Click += ClearButton_Click;
-            ClearButton.SetValue(Grid.RowProperty, 1);
-            ClearButton.SetValue(Grid.ColumnProperty, 0);
-            grid.Children.Add(ClearButton);
-
-            OKButton = new Button();
-            OKButton.Margin = new Thickness(5, 5, 0, 0);
-            OKButton.Content = "OK";
-            OKButton.Click += OKButton_Click;
-            OKButton.SetValue(Grid.RowProperty, 1);
-            OKButton.SetValue(Grid.ColumnProperty, 2);
-            OKButton.IsEnabled = false;
-            grid.Children.Add(OKButton);
-
-            var CancelButton = new Button();
-            CancelButton.Margin = new Thickness(5, 5, 0, 0);
-            CancelButton.Content = "Cancel";
-            CancelButton.Click += CancelButton_Click;
-            CancelButton.SetValue(Grid.RowProperty, 1);
-            CancelButton.SetValue(Grid.ColumnProperty, 3);
-            grid.Children.Add(CancelButton);
-        }
-        public bool ShowDialog(string? column = null, string? value = null, FilterType filtertype = FilterType.Contains) =>
-            ShowDialogInternal(null, column, value, filtertype);
-        public bool ShowDialog(string title) =>
-            ShowDialogInternal(title, null, null, default);
+        grid = new Grid();
+        grid.Margin = new Thickness(5);
+        grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1.0F, GridUnitType.Star) });
+        grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(40.0F, GridUnitType.Pixel) });
 
-        private bool ShowDialogInternal(string? title, string? column, string? value, FilterType filtertype)
-        {
-            window = new ThemableWindow
-            {
-                Title = title ?? "Select Items",
-                WindowStyle = WindowStyle.SingleBorderWindow,
-                Content = grid
-            };
-            datagrid.Refresh(true, true);
-            if (!column.IsNullOrWhiteSpace() && !value.IsNullOrWhiteSpace())
-                datagrid.AddVisualFilter(column, value, filtertype);
-            if (window.ShowDialog() == true)
-                return true;
-            return false;
-        }
+        grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(80.0F, GridUnitType.Pixel) });
+        grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1.0F, GridUnitType.Star) });
+        grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(80.0F, GridUnitType.Pixel) });
+        grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(80.0F, GridUnitType.Pixel) });
 
-        private Window GetWindow([CallerMemberName] string methodName = "")
+        datagrid = new DynamicDataGrid<T>();
+        
+        datagrid.Reconfigure(options =>
+        {
+            options.BeginUpdate();
+            options.Clear();
+            options.SelectColumns = true;
+            options.FilterRows = true;
+            if (multiselect)
+                options.MultiSelect = true;
+            options.EndUpdate();
+        });
+        datagrid.Reconfigure();
+        
+        datagrid.OnReload += Grid_OnReload;
+        datagrid.OnDoubleClick += Grid_DoubleClick;
+        datagrid.ColumnsTag = "MSD";
+        if (columns != null)
         {
-            return window ?? throw new Exception($"Must call ShowDialog() before {methodName}()");
+            _columns = columns;
+            foreach (var column in columns)
+                datagrid.AddHiddenColumn(column.Property);
+            //datagrid.HiddenColumns.AddRange(columns);
         }
-
-        public Guid[] IDs()
+        else
         {
-            var window = GetWindow();
-            if (window.DialogResult == true)
-            {
-                return datagrid.SelectedRows.ToArray(r => r.Get<T, Guid>(x => x.ID));
-            }
-            else if (window.DialogResult == false)
-            {
-                return [Guid.Empty];
-            }
-            else
-            {
-                return Array.Empty<Guid>();
-            }
+            var cols = LookupFactory.DefineColumns<T>()
+                .AddColumns(ColumnTypeFlags.IncludeOptional | ColumnTypeFlags.IncludeForeignKeys | ColumnTypeFlags.IncludeLinked);
+            foreach (var col in cols)
+                datagrid.AddHiddenColumn(col.ToString());
         }
 
-        public CoreTable Data()
+        var _settings = new UserConfiguration<MultiSelectDialogSettings>(datagrid.GetTag()).Load();
+        datagrid.FilterComponent.SetSettings(_settings.Filters,false);
+        datagrid.FilterComponent.OnFiltersSelected += (settings) =>
         {
-            var window = GetWindow();
+            var _settings = new MultiSelectDialogSettings() { Filters = settings };
+            new UserConfiguration<MultiSelectDialogSettings>(datagrid.GetTag()).Save(_settings);
+        };
+        
+        datagrid.SetValue(Grid.RowProperty, 0);
+        datagrid.SetValue(Grid.ColumnProperty, 0);
+        datagrid.SetValue(Grid.ColumnSpanProperty, 4);
+        datagrid.OnSelectItem += Datagrid_OnSelectItem;
+        grid.Children.Add(datagrid);
+        
+        ClearButton = new Button();
+        ClearButton.Margin = new Thickness(0, 5, 5, 0);
+        ClearButton.Content = "Clear";
+        ClearButton.Click += ClearButton_Click;
+        ClearButton.SetValue(Grid.RowProperty, 1);
+        ClearButton.SetValue(Grid.ColumnProperty, 0);
+        grid.Children.Add(ClearButton);
 
-            var result = new CoreTable();
-            result.Columns.Add(new CoreColumn { ColumnName = "ID", DataType = typeof(Guid) });
-            if(_columns is not null)
-            {
-                foreach (var column in _columns.Where(x => !string.Equals(x.Property, "ID")))
-                    result.Columns.Add(new CoreColumn { ColumnName = column.Property, DataType = column.Type });
-            }
+        OKButton = new Button();
+        OKButton.Margin = new Thickness(5, 5, 0, 0);
+        OKButton.Content = "OK";
+        OKButton.Click += OKButton_Click;
+        OKButton.SetValue(Grid.RowProperty, 1);
+        OKButton.SetValue(Grid.ColumnProperty, 2);
+        OKButton.IsEnabled = false;
+        grid.Children.Add(OKButton);
 
-            if (window.DialogResult == true)
-            {
-
-                if (datagrid?.Data != null && datagrid.SelectedRows.Length != 0)
-                    foreach (var sel in datagrid.SelectedRows)
-                    {
-                        var row = result.NewRow();
-                        foreach (var column in result.Columns)
-                        {
-                            var value = sel[column.ColumnName];
-                            row.Set(column.ColumnName, value);
-                        }
-                        result.Rows.Add(row);
-                    }
-            }
-            else if (window.DialogResult == false)
-            {
-                var row = result.NewRow(true);
-                result.Rows.Add(row);
-            }
+        var CancelButton = new Button();
+        CancelButton.Margin = new Thickness(5, 5, 0, 0);
+        CancelButton.Content = "Cancel";
+        CancelButton.Click += CancelButton_Click;
+        CancelButton.SetValue(Grid.RowProperty, 1);
+        CancelButton.SetValue(Grid.ColumnProperty, 3);
+        grid.Children.Add(CancelButton);
+    }
+    public bool ShowDialog(string? column = null, string? value = null, FilterType filtertype = FilterType.Contains) =>
+        ShowDialogInternal(null, column, value, filtertype);
+    public bool ShowDialog(string title) =>
+        ShowDialogInternal(title, null, null, default);
 
-            return result;
-        }
-        
-        public T[] Items(Columns<T>? columns = null)
+    private bool ShowDialogInternal(string? title, string? column, string? value, FilterType filtertype)
+    {
+        window = new ThemableWindow
         {
-            var window = GetWindow();
+            Title = title ?? "Select Items",
+            WindowStyle = WindowStyle.SingleBorderWindow,
+            Content = grid
+        };
+        datagrid.Refresh(true, true);
+        if (!column.IsNullOrWhiteSpace() && !value.IsNullOrWhiteSpace())
+            datagrid.AddVisualFilter(column, value, filtertype);
+        if (window.ShowDialog() == true)
+            return true;
+        return false;
+    }
 
-            if (window.DialogResult == true)
-            {
-                var ids = datagrid.SelectedRows.ToArray(r => r.Get<T, Guid>(x => x.ID));
-                if (ids.Length > 0)
-                {
-                    return new Client<T>().Query(new Filter<T>(x => x.ID).InList(ids), columns).ToArray<T>();
-                }
-            }
-            else if (window.DialogResult == false)
-                return [new T()];
+    private Window GetWindow([CallerMemberName] string methodName = "")
+    {
+        return window ?? throw new Exception($"Must call ShowDialog() before {methodName}()");
+    }
 
-            return [];
+    public Guid[] IDs()
+    {
+        var window = GetWindow();
+        if (window.DialogResult == true)
+        {
+            return datagrid.SelectedRows.ToArray(r => r.Get<T, Guid>(x => x.ID));
+        }
+        else if (window.DialogResult == false)
+        {
+            return [Guid.Empty];
         }
+        else
+        {
+            return Array.Empty<Guid>();
+        }
+    }
 
-        Entity[] IMultiSelectDialog.Items(IColumns? columns) => Items(columns as Columns<T>);
+    public CoreTable Data()
+    {
+        var window = GetWindow();
 
-        private void Grid_DoubleClick(object sender, HandledEventArgs args)
+        var result = new CoreTable();
+        result.Columns.Add(new CoreColumn { ColumnName = "ID", DataType = typeof(Guid) });
+        if(_columns is not null)
         {
-            args.Handled = true;
-            window!.DialogResult = true;
-            window.Close();
+            foreach (var column in _columns.Where(x => !string.Equals(x.Property, "ID")))
+                result.Columns.Add(new CoreColumn { ColumnName = column.Property, DataType = column.Type });
         }
 
-        private void Datagrid_OnSelectItem(object sender, DynamicGridSelectionEventArgs e)
+        if (window.DialogResult == true)
         {
-            OKButton.IsEnabled = e.Rows?.Any() == true;
-        }
 
-        private void CancelButton_Click(object sender, RoutedEventArgs e)
+            if (datagrid?.Data != null && datagrid.SelectedRows.Length != 0)
+                foreach (var sel in datagrid.SelectedRows)
+                {
+                    var row = result.NewRow();
+                    foreach (var column in result.Columns)
+                    {
+                        var value = sel[column.ColumnName];
+                        row.Set(column.ColumnName, value);
+                    }
+                    result.Rows.Add(row);
+                }
+        }
+        else if (window.DialogResult == false)
         {
-            window!.Close();
+            var row = result.NewRow(true);
+            result.Rows.Add(row);
         }
 
-        private void OKButton_Click(object sender, RoutedEventArgs e)
+        return result;
+    }
+    
+    public T[] Items(Columns<T>? columns = null)
+    {
+        var window = GetWindow();
+
+        if (window.DialogResult == true)
         {
-            window!.DialogResult = true;
-            window.Close();
+            var ids = datagrid.SelectedRows.ToArray(r => r.Get<T, Guid>(x => x.ID));
+            if (ids.Length > 0)
+            {
+                return new Client<T>().Query(new Filter<T>(x => x.ID).InList(ids), columns).ToArray<T>();
+            }
         }
+        else if (window.DialogResult == false)
+            return [new T()];
+
+        return [];
+    }
+
+    Entity[] IMultiSelectDialog.Items(IColumns? columns) => Items(columns as Columns<T>);
 
-        private void ClearButton_Click(object sender, RoutedEventArgs e)
+    private void Grid_DoubleClick(object sender, HandledEventArgs args)
+    {
+        args.Handled = true;
+        window!.DialogResult = true;
+        window.Close();
+    }
+
+    private void Datagrid_OnSelectItem(object sender, DynamicGridSelectionEventArgs e)
+    {
+        OKButton.IsEnabled = e.Rows?.Any() == true;
+    }
+
+    private void CancelButton_Click(object sender, RoutedEventArgs e)
+    {
+        window!.Close();
+    }
+
+    private void OKButton_Click(object sender, RoutedEventArgs e)
+    {
+        window!.DialogResult = true;
+        window.Close();
+    }
+
+    private void ClearButton_Click(object sender, RoutedEventArgs e)
+    {
+        window!.DialogResult = false;
+        window.Close();
+    }
+
+    private void Grid_OnReload(object sender, Filters<T> criteria, Columns<T> columns, ref SortOrder<T>? sortby)
+    {
+        if (_filter != null)
+            criteria.Add(_filter);
+    }
+
+    public static bool SelectItem([NotNullWhen(true)] out T? item, Filter<T>? filter = null, Columns<T>? columns = null, string? title = null)
+    {
+        var dlg = new MultiSelectDialog<T>(filter, columns, multiselect: false);
+        if (dlg.ShowDialogInternal(title, null, null, default))
         {
-            window!.DialogResult = false;
-            window.Close();
+            item = dlg.Data().ToObjects<T>().FirstOrDefault();
+            return item is not null;
         }
-
-        private void Grid_OnReload(object sender, Filters<T> criteria, Columns<T> columns, ref SortOrder<T>? sortby)
+        else
         {
-            if (_filter != null)
-                criteria.Add(_filter);
+            item = null;
+            return false;
         }
+    }
 
-        public static bool SelectItem([NotNullWhen(true)] out T? item, Filter<T>? filter = null, Columns<T>? columns = null, string? title = null)
+    public static bool SelectItems([NotNullWhen(true)] out T[]? items, Filter<T>? filter = null, Columns<T>? columns = null, string? title = null)
+    {
+        var dlg = new MultiSelectDialog<T>(filter, columns, multiselect: true);
+        if (dlg.ShowDialogInternal(title, null, null, default))
         {
-            var dlg = new MultiSelectDialog<T>(filter, columns, multiselect: false);
-            if (dlg.ShowDialogInternal(title, null, null, default))
-            {
-                item = dlg.Data().ToObjects<T>().FirstOrDefault();
-                return item is not null;
-            }
-            else
-            {
-                item = null;
-                return false;
-            }
+            items = dlg.Data().ToArray<T>();
+            return true;
         }
-
-        public static bool SelectItems([NotNullWhen(true)] out T[]? items, Filter<T>? filter = null, Columns<T>? columns = null, string? title = null)
+        else
         {
-            var dlg = new MultiSelectDialog<T>(filter, columns, multiselect: true);
-            if (dlg.ShowDialogInternal(title, null, null, default))
-            {
-                items = dlg.Data().ToArray<T>();
-                return true;
-            }
-            else
-            {
-                items = null;
-                return false;
-            }
+            items = null;
+            return false;
         }
     }
+}
+
+public static class MultiSelectDialog
+{
+    public static bool SelectItem<T>([NotNullWhen(true)] out T? item, Filter<T>? filter = null, Columns<T>? columns = null, string? title = null)
+        where T : Entity, IRemotable, IPersistent, new()
+    {
+        return MultiSelectDialog<T>.SelectItem(out item, filter: filter, columns: columns, title: title);
+    }
+
+    public static bool SelectItems<T>([NotNullWhen(true)] out T[]? items, Filter<T>? filter = null, Columns<T>? columns = null, string? title = null)
+        where T : Entity, IRemotable, IPersistent, new()
+    {
+        return MultiSelectDialog<T>.SelectItems(out items, filter: filter, columns: columns, title: title);
+    }
 }

+ 15 - 11
inabox.wpf/DynamicGrid/Grids/DynamicManyToManyGrid.cs

@@ -262,8 +262,8 @@ public class DynamicManyToManyGrid<TManyToMany, TThis> : DynamicGrid<TManyToMany
         var result = new List<Guid>();
         foreach (var item in WorkingList)
         {
-            //var prop = GetOtherLink(item);
-            var prop = GetThisLink(item);
+            var prop = GetOtherLink(item);
+            // var prop = GetThisLink(item);
             result.Add(prop.ID);
         }
 
@@ -275,13 +275,7 @@ public class DynamicManyToManyGrid<TManyToMany, TThis> : DynamicGrid<TManyToMany
     {
         var result = LookupFactory.DefineChildFilter(typeof(TThis), OtherType(), new[] { Item });
 
-        var filtertype = typeof(Filter<>).MakeGenericType(OtherType());
-
-        var filtermethod = filtertype.GetMethods(BindingFlags.Public | BindingFlags.Static).Where(x =>
-            x.Name.Equals("List") && x.GetParameters().Last().ParameterType.IsAssignableFrom(typeof(IEnumerable<Guid>))).First();
-        var filterexpression = CoreUtils.GetPropertyExpression(OtherType(), "ID");
-        var filtervalues = CurrentGuids();
-        var filter = filtermethod.Invoke(null, new object[] { filterexpression, ListOperator.Excludes, filtervalues }) as IFilter;
+        var filter = Filter.Create(OtherType(), "ID").NotInList(CurrentGuids());
 
         if (filter != null)
         {
@@ -305,11 +299,21 @@ public class DynamicManyToManyGrid<TManyToMany, TThis> : DynamicGrid<TManyToMany
             var filter = GetFilter();
 
             var dlgtype = typeof(MultiSelectDialog<>).MakeGenericType(OtherType());
-            var dlg = (Activator.CreateInstance(dlgtype, filter, null, true) as IMultiSelectDialog)!;
+            var columns = LookupFactory.DefineLookupColumns(typeof(TManyToMany), OtherType(), otherproperty.Name);
+            var prefix = otherproperty.Name + ".";
+            foreach(var column in DataColumns())
+            {
+                if(column.Property.StartsWith(prefix))
+                {
+                    columns.Add(column.Property[prefix.Length..]);
+                }
+            }
+
+            var dlg = (Activator.CreateInstance(dlgtype, filter, columns, true) as IMultiSelectDialog)!;
             if (dlg.ShowDialog())
             {
                 var guids = CurrentGuids();
-                foreach (var entity in dlg.Items(null))
+                foreach (var entity in dlg.Data().ToObjects(OtherType()).Cast<Entity>())
                 {
                     if (!guids.Contains(entity.ID))
                     {