using InABox.Clients; using InABox.Core; using InABox.WPF; using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Drawing; using System.Linq; using System.Reflection; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; namespace InABox.DynamicGrid; public class DynamicGridClientDataComponent : IDynamicGridDataComponent where T : Entity, IRemotable, IPersistent, new() { private readonly int ChunkSize = 500; public DynamicGrid Grid { get; set; } public delegate void OnReloadEventHandler(object sender, Filters criteria, Columns columns, ref SortOrder? sortby); public event OnReloadEventHandler? OnReload; public Column[] FilterColumns; public DynamicGridClientDataComponent(DynamicGrid grid) { Grid = grid; Grid.BeforeRefresh += Grid_BeforeRefresh; Grid.AfterRefresh += Grid_AfterRefresh; SetupFilterColumns(); } [MemberNotNull(nameof(FilterColumns))] private void SetupFilterColumns() { if (typeof(T).GetCustomAttribute() is AutoEntity auto) { if (auto.Generator is not null) { var columns = auto.Generator.IDColumns; FilterColumns = columns.Select(x => new Column(x.Property)).ToArray(); } else { FilterColumns = Array.Empty>(); } } else { FilterColumns = new[] { new Column(x => x.ID) }; } foreach (var column in FilterColumns) { Grid.AddHiddenColumn(column.Property); } } private CoreRow[]? SelectedBeforeRefresh; private void Grid_BeforeRefresh(object sender, BeforeRefreshEventArgs args) { SelectedBeforeRefresh = Grid.SelectedRows; } private void Grid_AfterRefresh(object sender, AfterRefreshEventArgs args) { if (SelectedBeforeRefresh is not null) { var selectedValues = SelectedBeforeRefresh .Select(x => FilterColumns.Select(c => x[c.Property]).ToList()) .ToList(); SelectedBeforeRefresh = null; var selectedRows = Grid.Data.Rows.Where(r => { return selectedValues.Any(v => { for (int i = 0; i < v.Count; ++i) { if (v[i]?.Equals(r[FilterColumns[i].Property]) != true) return false; } return true; }); }).ToArray(); Grid.SelectedRows = selectedRows; Grid.SelectItems(selectedRows); } } public Columns LoadEditorColumns() { return DynamicGridUtils.LoadEditorColumns(Grid.DataColumns()); } private Filter? GetRowFilter(CoreRow row) { var newFilters = new Filters(); foreach (var column in FilterColumns) { newFilters.Add(new Filter(column.Property).IsEqualTo(row[column.Property])); } return newFilters.Combine(); } public void DeleteItems(CoreRow[] rows) { var deletes = new List(); foreach (var row in rows) { var delete = new T(); foreach (var column in FilterColumns) { CoreUtils.SetPropertyValue(delete, column.Property, row[column.Property]); } //var delete = /* row.ToObject(); */ deletes.Add(delete); } Client.Delete(deletes, "Deleted on User Request"); } public T LoadItem(CoreRow row) { var id = row.Get(x => x.ID); var filter = GetRowFilter(row);//new Filter(x => x.ID).IsEqualTo(id); return Client.Query(filter, LoadEditorColumns()).ToObjects().FirstOrDefault() ?? throw new Exception($"No {typeof(T).Name} with ID {id}"); } public T[] LoadItems(CoreRow[] rows) { Filter? filter = null; var results = new List(); for (var i = 0; i < rows.Length; i += ChunkSize) { var chunk = rows.Skip(i).Take(ChunkSize); foreach (var row in chunk) { var newFilter = GetRowFilter(row); if (newFilter is not null) { //var id = row.Get(x => x.ID); if (filter is null) filter = newFilter;//new Filter(x => x.ID).IsEqualTo(id); else filter = filter.Or(newFilter);//.Or(x => x.ID).IsEqualTo(id); } } var columns = LoadEditorColumns(); // new Columns().Default(ColumnType.IncludeOptional, ColumnType.IncludeForeignKeys, ColumnType.IncludeUserProperties); var data = Client.Query(filter, columns); results.AddRange(data.ToObjects()); } return results.ToArray(); } public void SaveItem(T item) { Client.Save(item, "Edited by User"); } public void SaveItems(T[] items) { Client.Save(items, "Edited by User"); } public void Reload( Filters criteria, Columns columns, SortOrder? sort, CancellationToken token, Action action) { OnReload?.Invoke(this, criteria, columns, ref sort); if(Grid.Options.PageSize > 0) { var inSort = sort; Task.Run(() => { var page = CoreRange.Database(Grid.Options.PageSize); var filter = criteria.Combine(); while (!token.IsCancellationRequested) { try { var data = Client.Query(filter, columns, inSort, page); data.Offset = page.Offset; if (token.IsCancellationRequested) { break; } var paged = data.Rows.Count == page.Limit; action(new(data, paged)); if (!paged) break; // Proposal - Let's slow it down a bit to enhance UI responsiveness? Thread.Sleep(100); page.Next(); } catch (Exception e) { action(new(e)); break; } } }, token); } else { Client.Query(criteria.Combine(), columns, sort, (data, e) => action(data is not null ? new(data) : new(e!))); } } }