DynamicGridClientDataComponent.cs 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. using InABox.Clients;
  2. using InABox.Core;
  3. using InABox.WPF;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Diagnostics.CodeAnalysis;
  7. using System.Drawing;
  8. using System.Linq;
  9. using System.Reflection;
  10. using System.Text;
  11. using System.Threading;
  12. using System.Threading.Tasks;
  13. using System.Windows;
  14. using System.Windows.Controls;
  15. namespace InABox.DynamicGrid;
  16. public class DynamicGridClientDataComponent<T> : IDynamicGridDataComponent<T>
  17. where T : Entity, IRemotable, IPersistent, new()
  18. {
  19. private readonly int ChunkSize = 500;
  20. public DynamicGrid<T> Grid { get; set; }
  21. public delegate void OnReloadEventHandler(object sender, Filters<T> criteria, Columns<T> columns, ref SortOrder<T>? sortby);
  22. public event OnReloadEventHandler? OnReload;
  23. public Column<T>[] FilterColumns;
  24. public DynamicGridClientDataComponent(DynamicGrid<T> grid)
  25. {
  26. Grid = grid;
  27. Grid.BeforeRefresh += Grid_BeforeRefresh;
  28. Grid.AfterRefresh += Grid_AfterRefresh;
  29. SetupFilterColumns();
  30. }
  31. [MemberNotNull(nameof(FilterColumns))]
  32. private void SetupFilterColumns()
  33. {
  34. if (typeof(T).GetCustomAttribute<AutoEntity>() is AutoEntity auto)
  35. {
  36. if (auto.Generator is not null)
  37. {
  38. var columns = auto.Generator.IDColumns;
  39. FilterColumns = columns.Select(x => new Column<T>(x.Property)).ToArray();
  40. }
  41. else
  42. {
  43. FilterColumns = Array.Empty<Column<T>>();
  44. }
  45. }
  46. else
  47. {
  48. FilterColumns = new[] { new Column<T>(x => x.ID) };
  49. }
  50. foreach (var column in FilterColumns)
  51. {
  52. Grid.AddHiddenColumn(column.Property);
  53. }
  54. }
  55. private CoreRow[]? SelectedBeforeRefresh;
  56. private void Grid_BeforeRefresh(object sender, BeforeRefreshEventArgs args)
  57. {
  58. SelectedBeforeRefresh = Grid.SelectedRows;
  59. }
  60. private void Grid_AfterRefresh(object sender, AfterRefreshEventArgs args)
  61. {
  62. if (SelectedBeforeRefresh is not null)
  63. {
  64. var selectedValues = SelectedBeforeRefresh
  65. .Select(x => FilterColumns.Select(c => x[c.Property]).ToList())
  66. .ToList();
  67. SelectedBeforeRefresh = null;
  68. var selectedRows = Grid.Data.Rows.Where(r =>
  69. {
  70. return selectedValues.Any(v =>
  71. {
  72. for (int i = 0; i < v.Count; ++i)
  73. {
  74. if (v[i]?.Equals(r[FilterColumns[i].Property]) != true)
  75. return false;
  76. }
  77. return true;
  78. });
  79. }).ToArray();
  80. Grid.SelectedRows = selectedRows;
  81. Grid.SelectItems(selectedRows);
  82. }
  83. }
  84. public Columns<T> LoadEditorColumns()
  85. {
  86. return DynamicGridUtils.LoadEditorColumns(Grid.DataColumns());
  87. }
  88. private Filter<T>? GetRowFilter(CoreRow row)
  89. {
  90. var newFilters = new Filters<T>();
  91. foreach (var column in FilterColumns)
  92. {
  93. newFilters.Add(new Filter<T>(column.Property).IsEqualTo(row[column.Property]));
  94. }
  95. return newFilters.Combine();
  96. }
  97. public void DeleteItems(CoreRow[] rows)
  98. {
  99. var deletes = new List<T>();
  100. foreach (var row in rows)
  101. {
  102. var delete = new T();
  103. foreach (var column in FilterColumns)
  104. {
  105. CoreUtils.SetPropertyValue(delete, column.Property, row[column.Property]);
  106. }
  107. //var delete = /* row.ToObject<TEntity>(); */
  108. deletes.Add(delete);
  109. }
  110. Client.Delete(deletes, "Deleted on User Request");
  111. }
  112. public T LoadItem(CoreRow row)
  113. {
  114. var id = row.Get<T, Guid>(x => x.ID);
  115. var filter = GetRowFilter(row);//new Filter<TEntity>(x => x.ID).IsEqualTo(id);
  116. return Client.Query(filter, LoadEditorColumns()).ToObjects<T>().FirstOrDefault()
  117. ?? throw new Exception($"No {typeof(T).Name} with ID {id}");
  118. }
  119. public T[] LoadItems(CoreRow[] rows)
  120. {
  121. Filter<T>? filter = null;
  122. var results = new List<T>();
  123. for (var i = 0; i < rows.Length; i += ChunkSize)
  124. {
  125. var chunk = rows.Skip(i).Take(ChunkSize);
  126. foreach (var row in chunk)
  127. {
  128. var newFilter = GetRowFilter(row);
  129. if (newFilter is not null)
  130. {
  131. //var id = row.Get<TEntity, Guid>(x => x.ID);
  132. if (filter is null)
  133. filter = newFilter;//new Filter<TEntity>(x => x.ID).IsEqualTo(id);
  134. else
  135. filter = filter.Or(newFilter);//.Or(x => x.ID).IsEqualTo(id);
  136. }
  137. }
  138. var columns = LoadEditorColumns(); // new Columns<TEntity>().Default(ColumnType.IncludeOptional, ColumnType.IncludeForeignKeys, ColumnType.IncludeUserProperties);
  139. var data = Client.Query(filter, columns);
  140. results.AddRange(data.ToObjects<T>());
  141. }
  142. return results.ToArray();
  143. }
  144. public void SaveItem(T item)
  145. {
  146. Client.Save(item, "Edited by User");
  147. }
  148. public void SaveItems(T[] items)
  149. {
  150. Client.Save(items, "Edited by User");
  151. }
  152. public void Reload(
  153. Filters<T> criteria, Columns<T> columns, SortOrder<T>? sort,
  154. CancellationToken token, Action<QueryResult> action)
  155. {
  156. OnReload?.Invoke(this, criteria, columns, ref sort);
  157. if(Grid.Options.PageSize > 0)
  158. {
  159. var inSort = sort;
  160. Task.Run(() =>
  161. {
  162. var page = CoreRange.Database(Grid.Options.PageSize);
  163. var filter = criteria.Combine();
  164. while (!token.IsCancellationRequested)
  165. {
  166. try
  167. {
  168. var data = Client.Query(filter, columns, inSort, page);
  169. data.Offset = page.Offset;
  170. if (token.IsCancellationRequested)
  171. {
  172. break;
  173. }
  174. var paged = data.Rows.Count == page.Limit;
  175. action(new(data, paged));
  176. if (!paged)
  177. break;
  178. // Proposal - Let's slow it down a bit to enhance UI responsiveness?
  179. Thread.Sleep(100);
  180. page.Next();
  181. }
  182. catch (Exception e)
  183. {
  184. action(new(e));
  185. break;
  186. }
  187. }
  188. }, token);
  189. }
  190. else
  191. {
  192. Client.Query(criteria.Combine(), columns, sort, (data, e) => action(data is not null ? new(data) : new(e!)));
  193. }
  194. }
  195. }